<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>勇气</title><link>https://courages.us/</link><description>Recent content on 勇气</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 12 Apr 2023 21:33:27 +0800</lastBuildDate><atom:link href="https://courages.us/index.xml" rel="self" type="application/rss+xml"/><item><title>mTLS 认证</title><link>https://courages.us/mtls-%E8%AE%A4%E8%AF%81/</link><pubDate>Wed, 12 Apr 2023 21:18:30 +0800</pubDate><guid>https://courages.us/mtls-%E8%AE%A4%E8%AF%81/</guid><description>&lt;p&gt;有时候虽然我们部署一个服务到了公网，但只想提供给部分用户而不想其他人（黑客/robot）使用，比如webhook或者跨机房的服务调用。虽然我们可以使用密码/token保护这些服务，但是程序可以被直接扫描到，仍然存在被攻击的风险。而如果把这些服务放在某个认证服务器后面，又存在二次登陆的问题。如何标识目标用户又不影响请求过程？答案是mTLS认证。&lt;br&gt;&#10;TLS认证是当前WEB通信的基石，没有加密的通信无异于裸奔：任何中间人都可以查看/串改通信内容。mTLS认证，亦即双向TLS认证，不但客户端校验服务器证书，服务器亦校验客户端证书，这意味着如果客户端证书不在服务器的信任列表里面，那么客户端也访问不了服务。请求认证过程如下&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2023/04/how_mtls_works-what_is_mutual_tls.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="654px" data-flex-grow="272" height="110" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2023/04/how_mtls_works-what_is_mutual_tls-300x110.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;mTLS可以用来保护私有服务，加强通信过程，减少服务器攻击。由于客户端也需要提供证书，证书里面可以携带用户或者设备信息，可以识别仅授信用户，才授权访问 。由于服务器需要校验客户端信息，所以未提供有效证书用户不能访问，就算盗取了用户的密码/token也不可以。因为双方都互相校验证书，所以也可以抵抗中间人攻击。这样子我们便可以公开服务，但又限制某些用户使用了。&lt;br&gt;&#10;mTLS认证有别于应用程序认证。mTLS仅涉及证书校验，在网关出就可以进行，不需要涉及应用程序逻辑/数据库。mTLS也不依赖于请求头/请求体里面的内容，所以不会影响已有程序。&lt;br&gt;&#10;mTLS认证限制某些用户/设备访问，也有别于传统VPN网络。VPN总是要求服务端/客户端先建立连接，才能在同一内网内访问。一旦连接建立，便可以访问所有服务。而采用mTLS认证，则每一个服务都可以使用不同的客户端证书，限制不同的用户访问。零信任（ZeroTrust）亦建立在mTLS之上，即对每个请求都做双向认证。&lt;br&gt;&#10;mTLS并不是什么新鲜事物，许多互联网软件都支持，比如浏览器、SSH，SSH采用私钥登陆的过程，即双向认证：客户端先将自己的公钥上传至服务器，建立连接时，客户端询问是否信任服务器，服务器亦校验客户端。Git使用SSH key登陆也是类似双向认证。开发者调用Google云服务，除了app认证信息，也是需要双向认证的。有些互联网公司也采用双向认证来保护自己的应用，比如支付功能，甚至是所有页面-只允许自己的APP查看，其他免谈。&lt;br&gt;&#10;Nginx早已支持mTLS认证，除了服务器本身的证书，还需要配置客户端证书或其签发root CA证书。关于服务器证书获取之前已介绍&lt;a class="link" href="https://courages.us/lets-encrypt/" target="_blank" rel="noopener"&#10; &gt;基于DNS自动获取证书&lt;/a&gt;了，同样的方法也可以用来生成客户端证书，比如基于用户id来生成不同域名username.id.example.com的证书给客户端使用。这里介绍另外一种基于&lt;a class="link" href="https://github.com/go-acme/lego" target="_blank" rel="noopener"&#10; &gt;LEGO ACME&lt;/a&gt;在本地生成客户端证书的方法。&lt;br&gt;&#10;首先安装lego程序，如果有golang环境直接就好了，或者下载对应平台的&lt;a class="link" href="https://github.com/go-acme/lego/releases" target="_blank" rel="noopener"&#10; &gt;程序&lt;/a&gt;。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ go install github.com/go-acme/lego/v4/cmd/lego@latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就可以基于&lt;a class="link" href="https://go-acme.github.io/lego/dns/" target="_blank" rel="noopener"&#10; &gt;DNS厂商&lt;/a&gt;来生成证书，这里以腾讯云DNS，注意它的APP Key是不同于DNSPod的。如果网络不加，建议延长TIMEOUT时间。这里一并生成浏览器/系统可用的PKCS12文件(.pfx)&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ TENCENTCLOUD_SECRET_ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;*** TENCENTCLOUD_PROPAGATION_TIMEOUT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;120&lt;/span&gt; TENCENTCLOUD_POLLING_INTERVAL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TENCENTCLOUD_SECRET_KEY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;***&lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lego --email username@exmaple.com --pem --pfx --pfx.pass *** --cert.timeout &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt; --dns tencentcloud --domains user1.idt.exmaple.com run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:46 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Obtaining bundled SAN certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/217627103547&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Could not find solver &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: tls-alpn-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Could not find solver &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: http-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: use dns-01 solver&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:47 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Preparing to solve DNS-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:50 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Trying to solve DNS-01&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:50 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Checking DNS record propagation using &lt;span style="color:#f92672"&gt;[&lt;/span&gt;127.0.0.53:53&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:55 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Wait &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; propagation &lt;span style="color:#f92672"&gt;[&lt;/span&gt;timeout: 2m0s, interval: 5s&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:42:55 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:01 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:06 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:11 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:17 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:22 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS record propagation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:35 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The server validated our request&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:35 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Cleaning DNS-01 challenge&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; acme: Validations succeeded; requesting certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2023/04/08 11:43:39 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;user1.idt.exmaple.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Server responded with a certificate.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -la .lego/certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 10:58 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;5341&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;3751&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.issuer.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;244&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;227&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;5568&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw------- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; channing channing &lt;span style="color:#ae81ff"&gt;2992&lt;/span&gt; 4月 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 11:43 user1.idt.exmaple.com.pfx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于这个证书的CA是Let’s Encrypt的，而Let’s Encrypt本身的证书又是Internet Security Research Group签发。而当Nginx配置ssl_client_certificate CA证书时只能是Root CA，也就是ISRG的证书，而不是中间厂商的证书，也就是不能用Let’s Encrypt的CA证书。ISRG的证书可以从浏览器导出或者网上&lt;a class="link" href="http://www.certificate.fyicenter.com/11138_ISRG_Root_X1_Certificate-79B459E67BB6E5E40173800888C81A58F6E99B6E.html" target="_blank" rel="noopener"&#10; &gt;下载&lt;/a&gt;，然后保存到服务器上&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mv isrg_root.crt /etc/nginx/certs/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chomd &lt;span style="color:#ae81ff"&gt;400&lt;/span&gt; etc/nginx/certs/isrg_root.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nginx配置如下，可以将日志级别设置为debug,调试/观察认证&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/nginx/conf.d/site-available/100-mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name mtls.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;301&lt;/span&gt; https://$host$request_uri;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt; ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name mtls.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_client_certificate /etc/nginx/conf.d/certs/isrg_root.crt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_client on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_depth 2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_session_cache builtin:1000 shared:SSL:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_prefer_server_ciphers on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# error_log /var/log/nginx/error.log debug;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /var/www/mtls.example.com/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index index.html index.htm;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;502&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;503&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;504&lt;/span&gt; /50x.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /50x.html &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用curl测试一下，提示需要客户端证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;400 No required SSL certificate was sent&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;body bgcolor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;white&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h1&amp;gt;400 Bad Request&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;center&amp;gt;No required SSL certificate was sent&amp;lt;/center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;hr&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;center&amp;gt;nginx/1.14.0&amp;lt;/center&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当带上证书的时候就可以了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --cert user1.idt.exmaple.com.crt --key user1.idt.exmaple.com.key https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;title&amp;gt;Welcome to mtls.example.com!&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1&amp;gt;Success! The mtls server is working!&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用浏览器访问目标网站需要安装.pfx文件，否则也会报错，禁止访问。通常Windows/Mac双击.pfx文件即可自动安，也可以通过浏览器配置来安装。使用Chrome需要在从菜单设置-&amp;gt;隐私设置和安全性-&amp;gt;安全-&amp;gt;管理设备证书-&amp;gt;个人-&amp;gt;导入。使用Firefox则是从从菜单设置-&amp;gt;隐私与安全-&amp;gt;安全-&amp;gt;查看证书-&amp;gt;您的证书-&amp;gt;导入。iOS和Android可以通过邮件的方式将.pfx文件传输到手机上，点击.pfx文件按照系统提示安装即可。最后使用浏览器打开https://mtls.example.com，会提示使用刚才配置好的证书，选择即可。&lt;br&gt;&#10;上面Nginx配置的是公共CA的根证书（isrg_root.crt），这意味着所有该CA签发的证书都将可以访问https://mtls.example.com，这有点太开放了。如果我们自己生成Root CA证书，便可以做进一步的控制。&lt;br&gt;&#10;首先生成Root CA证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl genrsa -des3 -out ca.key &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter PEM pass phrase:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying - Enter PEM pass phrase:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl req -new -x509 -days &lt;span style="color:#ae81ff"&gt;3650&lt;/span&gt; -key ca.key -out ca.crt39:06&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter pass phrase &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ca.key:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You are about to be asked to enter information that will be incorporated&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;into your certificate request.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What you are about to enter is what is called a Distinguished Name or a DN.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are quite a few fields but you can leave some blank&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For some fields there will be a default value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you enter &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, the field will be left blank.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Country Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; letter code&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;AU&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State or Province Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;full name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Some-State&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locality Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, city&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organization Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, company&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organizational Unit Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, section&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Common Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;e.g. server FQDN or YOUR name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Email Address &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat ca.key &amp;gt; ca.pem &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cat ca.crt &amp;gt;&amp;gt; ca.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ca.crt ca.key ca.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后使用CA证书生成客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl genrsa -out user1.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter PEM pass phrase:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl req -new -key user1.key -out user1.csr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You are about to be asked to enter information that will be incorporated&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;into your certificate request.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What you are about to enter is what is called a Distinguished Name or a DN.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are quite a few fields but you can leave some blank&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For some fields there will be a default value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you enter &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, the field will be left blank.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Country Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; letter code&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;AU&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State or Province Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;full name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Some-State&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locality Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, city&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organization Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, company&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organizational Unit Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, section&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Common Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;e.g. server FQDN or YOUR name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Email Address &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please enter the following &lt;span style="color:#e6db74"&gt;&amp;#39;extra&amp;#39;&lt;/span&gt; attributes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;to be sent with your certificate request&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A challenge password &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;An optional company name &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl x509 -req -days &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; -in user1.csr -CA ca.crt -CAkey ca.key -set_serial &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; -out user1.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Certificate request self-signature ok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter pass phrase &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ca.key:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl pkcs12 -export -out user1.pfx -inkey user1.key -in user1.crt -certfile ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter Export Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying - Enter Export Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后将ca.crt上传至服务器/etc/nginx/certs/下面并配置ssl_client_certificate使用该证书即可。使用curl测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --cert user1.crt --key user1.key https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;title&amp;gt;Welcome to mtls.example.com!&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1&amp;gt;Success! The mtls server is working!&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样可以成功访问。不过刚才生成的.pfx文件只有Firefox可以导入使用，其他系统/浏览器不可以，那么可以从Firefox中重新备份导出该文件，Chrome/其他系统就可以使用了。或者重新转换一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl pkcs12 -in user1.pfx -out user1.pem -nodes &lt;span style="color:#75715e"&gt;#pfx证书转换为x.509格式的pem证书&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl pkcs12 -in user1.pfx -nocerts -nodes -out user1.key &lt;span style="color:#75715e"&gt;#pfx证书中提取密钥对&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl rsa -in user1.key -out user1_private.key &lt;span style="color:#75715e"&gt;#密钥对提取私钥&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl pkcs12 -export -in user1.pem -inkey user1_private.key -out user1.pfx &lt;span style="color:#75715e"&gt;#使用x.509+私钥转换为win10可用的pfx证书&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用自定义CA可以有效控制证书的签发，也可以免CA直接签发客户端证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ openssl req -x509 -nodes -days &lt;span style="color:#ae81ff"&gt;9999&lt;/span&gt; -newkey rsa:2048 -keyout user2.key -out user2.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;..+...+...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You are about to be asked to enter information that will be incorporated&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;into your certificate request.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What you are about to enter is what is called a Distinguished Name or a DN.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There are quite a few fields but you can leave some blank&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For some fields there will be a default value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;If you enter &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;, the field will be left blank.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Country Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; letter code&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;AU&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;State or Province Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;full name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Some-State&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Locality Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, city&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organization Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, company&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Organizational Unit Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;eg, section&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Common Name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;e.g. server FQDN or YOUR name&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Email Address &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;无CA签名的证书，就直接将user2.crt上传至服务器/etc/nginx/certs/下面并配置ssl_client_certificate使用该证书即可。如果生成了多个，就合并成一个上传服务器就好了。使用curl测试一下，也是可以的&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --cert user2.crt --key user2.key https://mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;title&amp;gt;Welcome to mtls.example.com!&amp;lt;/title&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1&amp;gt;Success! The mtls server is working!&amp;lt;/h1&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nginx还支持将客户端证书及CA的DN传递给后端程序，再配合访问控制，便可以精细控制用户访问了。Nginx配置如下，注意这里ssl_verify_client是optional,认证失败不再返回400而是403&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/nginx/conf.d/site-available/100-mtls.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt; ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name mtls.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/example.comfullchain.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_client_certificate /etc/nginx/conf.d/certs/ca.crt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_client optional;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_verify_depth 2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_session_cache builtin:1000 shared:SSL:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_prefer_server_ciphers on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# error_log /var/log/nginx/error.log debug;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# if ($ssl_client_i_dn != &amp;#34;/C=EX/CN=Client/emailAddress=user1@example.com&amp;#34;) {&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# return 403;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# }&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;$ssl_client_verify !&lt;span style="color:#f92672"&gt;=&lt;/span&gt; SUCCESS&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; 403; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header SSL_Client_Issuer $ssl_client_i_dn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header SSL_Client $ssl_client_s_dn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header SSL_Client_Verify $ssl_client_verify;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:3000/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;502&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;503&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;504&lt;/span&gt; /50x.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /50x.html &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;NodeJS代码如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;express&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;port&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;express&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;) =&amp;gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;res&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;status&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;`Hello &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ssl_client&amp;#34;&lt;/span&gt;)&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, your certificate was issued by &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;SSL_Client_Issuer&amp;#34;&lt;/span&gt;)&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;!`&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;listen&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;port&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;host&lt;/span&gt;, () =&amp;gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;listening&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用curl测试一下便会输出客户端DN。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ curl --cert user1.crt --key user1.key https://mtls.example.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Hello emailAddress=user1@example,CN=exmaple,OU=server,C=exmaple, your certificate was issued by emailAddress=user1@example,CN=exmaple,OU=user1,C=exmaple!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;事实上不仅Nginx支持设置客户端认证，&lt;a class="link" href="https://github.com/Kong/kong" target="_blank" rel="noopener"&#10; &gt;Kong网关&lt;/a&gt;，云原生应用传输&lt;a class="link" href="https://github.com/traefik/traefik" target="_blank" rel="noopener"&#10; &gt;traefik&lt;/a&gt;等也早已支持，编程语言层面更是支持开发mTLS应用了。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/" target="_blank" rel="noopener"&#10; &gt;What is mutual TLS (mTLS)?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dapenti.com/blog/index.asp" target="_blank" rel="noopener"&#10; &gt;Mutual authentication&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/haoel/mTLS" target="_blank" rel="noopener"&#10; &gt;mTLS Golang Example&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://datacadamia.com/web/server/nginx/client_authentication" target="_blank" rel="noopener"&#10; &gt;How to configure certification based client authentication with Nginx ?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://dev.to/darshitpp/how-to-implement-two-way-ssl-with-nginx-2g39" target="_blank" rel="noopener"&#10; &gt;How To Implement Two Way SSL With Nginx&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/pandashavenobugs/mTLS-with-node-blogpost" target="_blank" rel="noopener"&#10; &gt;mTLS with node&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://medium.com/geekculture/mtls-with-nginx-and-nodejs-e3d0980ed950" target="_blank" rel="noopener"&#10; &gt;mTLS with NGINX and NodeJS&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://go-acme.github.io/lego/" target="_blank" rel="noopener"&#10; &gt;LEGO&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.infinisign.com/faq/firefox-pfx-import-windows10-error-password" target="_blank" rel="noopener"&#10; &gt;Firefox导出PFX证书在Win10导入提示密码错误&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/8431528/nginx-ssl-certificate-authentication-signed-by-intermediate-ca-chain" target="_blank" rel="noopener"&#10; &gt;NGinx SSL certificate authentication signed by intermediate CA (chain)&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Android平板安装Termux和LunarVim</title><link>https://courages.us/android%E5%B9%B3%E6%9D%BF%E5%AE%89%E8%A3%85termux%E5%92%8Clunarvim/</link><pubDate>Sun, 20 Nov 2022 22:03:18 +0800</pubDate><guid>https://courages.us/android%E5%B9%B3%E6%9D%BF%E5%AE%89%E8%A3%85termux%E5%92%8Clunarvim/</guid><description>&lt;p&gt;这次趁着双11买了个小米平板5pro，才发现不过是大号手机而已，系统是基于Android 11的MIUI 13。除了WPS，bilibili、浏览器都不过兼容桌面模式而已，然而却又失去了移动设备的便利性：touch事件不能精确响应，于是卸掉重新安装的普通版。终于体会到了雪球不明真相群众的那句话：平板上的东西已经在手机上进化完了。想想这个平板除了刷视频、看书、画画，还能干点啥？看代码应该也有优势，毕竟分辨率还不错。Android上并没有什么好用的代码App，虽然可以安装Github查看代码，但还是看不了几行，也不如IDE来的方便。幸好还有&lt;a class="link" href="https://termux.dev/" target="_blank" rel="noopener"&#10; &gt;Termux&lt;/a&gt;，极大的拓展了Android的可用性，增加了超过1万个cli应用，比如比应用市场上任何服务器连接App都好用的ssh，强大的编程开发工具&lt;a class="link" href="https://www.lunarvim.org" target="_blank" rel="noopener"&#10; &gt;LunarVim&lt;/a&gt;。&lt;br&gt;&#10;&lt;a class="link" href="https://termux.dev/" target="_blank" rel="noopener"&#10; &gt;Termux&lt;/a&gt;是一个Android终端（terminal）模拟软件并提供Linux环境，可以安装许多Linux下常见软件，比如ssh、git、curl，和各种开发软件，比如nodejs、python、rust、golang等等。Termux既可以从&lt;a class="link" href="https://github.com/termux/termux-app" target="_blank" rel="noopener"&#10; &gt;GitHub&lt;/a&gt;上下载安装，也可以使用&lt;a class="link" href="https://f-droid.org" target="_blank" rel="noopener"&#10; &gt;F-Droid&lt;/a&gt;安装。使用F-Droid的好处在于可以自动更新，和管理其他的扩展，比如Termux:Styling、Termux:API。安装完成后记得给予联网权限，如果安装了其他的扩展，记得在安全中心－联网管理中找到对应的扩展App也给予联网权限，否则Termux就上不了网。 安装完成后打开Termux，这里注意Termux重置了目录，所有目录都是在data/data/com.termux/files/下面，并提供了两个快捷访问$HOME: data/data/com.termux/files/home和$PREFIX: /data/data/com.termux/files/usr。运行下面的命令设置一下存储和文件夹软链接，这样方便Termux与外部目录(比如Downloads）互相复制粘贴&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;termux-setup-storage&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以更改一些配置，比如软键盘快捷键之类的&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim ~/.termux/termux.properties&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#重新加载配置&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;termux-reload-settings&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#更改使用的源仓库，默认使用多仓库，可以改为使用单一仓库，比如清华源&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;termux-change-repo&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装一些基础软件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pkg install openssh git curl wget vim bat croc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装oh-my-zsh和自动补全插件，其他插件的安装与正常安装无差别&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pkg install zsh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sh -c &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/zsh-users/zsh-autosuggestions &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;ZSH_CUSTOM&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;~/.oh-my-zsh/custom&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/plugins/zsh-autosuggestions&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后编辑~/.zshrc，更改主题和插件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ZSH_THEME=&amp;#34;robbyrussell&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ZSH_THEME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;agnoster&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Which plugins would you like to load?&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Standard plugins can be found in $ZSH/plugins/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Custom plugins may be added to $ZSH_CUSTOM/plugins/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Example format: plugins=(rails git textmate ruby lighthouse)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Add wisely, as too many plugins slow down shell startup.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plugins&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;git zsh-autosuggestions&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果zsh显示乱码的话，可以按住屏幕在弹出的more菜单里面更改nerd font字体，比如ubuntu。&lt;br&gt;&#10;现在可以开始安装LunarVim的依赖&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pkg install neovim build-essential python vim-python nodejs rust fd ripgrep&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装完成完成后neovim, make，npm，pip，cargo也都安装好了。这时候就可以使用nvim来编辑了，可以参考:help nvim/:Tutor进行学习。这里顺便安装了pyhon vim的交互包，等下可以跳过python依赖的安装。还安装了两个rust写的神器：文件查找&lt;a class="link" href="https://github.com/sharkdp/fd" target="_blank" rel="noopener"&#10; &gt;fd&lt;/a&gt;和文件内容搜索&lt;a class="link" href="https://github.com/BurntSushi/ripgrep" target="_blank" rel="noopener"&#10; &gt;ripgrep&lt;/a&gt;，等下也可以跳过rust依赖安装。，&lt;br&gt;&#10;&lt;a class="link" href="https://www.lunarvim.org/" target="_blank" rel="noopener"&#10; &gt;LunarVim&lt;/a&gt;是一个基于&lt;a class="link" href="https://neovim.io/" target="_blank" rel="noopener"&#10; &gt;Neovim&lt;/a&gt;开发的IDE，打包了文件搜索、内容查找、代码补全，语法高亮等许多功能，这个可比简单vim强多了，更多功能、特点可以在官网视频学习。官方提供的安装脚本并不包含Termux的，我们下载下来看一下是否都已经安装好依赖、做一些改动&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl https://raw.githubusercontent.com/lunarvim/lunarvim/master/utils/installer/install.sh &amp;gt; install.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里稍微改一下，匹配不到OS就使用pkg安装&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; detect_platform&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$OS&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; in&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Linux&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f &lt;span style="color:#e6db74"&gt;&amp;#34;/etc/arch-release&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f &lt;span style="color:#e6db74"&gt;&amp;#34;/etc/artix-release&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RECOMMEND_INSTALL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sudo pacman -S&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f &lt;span style="color:#e6db74"&gt;&amp;#34;/etc/fedora-release&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f &lt;span style="color:#e6db74"&gt;&amp;#34;/etc/redhat-release&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RECOMMEND_INSTALL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sudo dnf install -y&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f &lt;span style="color:#e6db74"&gt;&amp;#34;/etc/gentoo-release&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RECOMMEND_INSTALL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;emerge -tv&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#75715e"&gt;# it&amp;#39;s termux&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RECOMMEND_INSTALL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;pkg install -y&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后开始安装LunarVim&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x install.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export LV_BRANCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;release-1.2/neovim-0.8&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./install.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 88&lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_|&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;888888$&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 888888&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 888888&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;888888&lt;span style="color:#ae81ff"&gt;\8&lt;/span&gt;888&lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; __88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;___88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; __88&lt;span style="color:#ae81ff"&gt;\\&lt;/span&gt;88&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; _88 _88&lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | 888888$ |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_|&lt;span style="color:#ae81ff"&gt;\8&lt;/span&gt;8&lt;span style="color:#ae81ff"&gt;\8&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; / &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; / &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; / &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; __88 |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;\8&lt;/span&gt;8$ / &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;\8&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;88888&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;\8&lt;/span&gt;88888$ |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;\$&lt;/span&gt; / &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; | &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_| &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_____/ &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_| &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_| &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;______|&lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_| &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;/ &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_|&lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_| &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_| &lt;span style="color:#ae81ff"&gt;\_&lt;/span&gt;_|&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Detecting platform &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; managing any additional neovim dependencies&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Would you like to install LunarVim&lt;span style="color:#e6db74"&gt;&amp;#39;s NodeJS dependencies?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[y]es or [n]o (default: no) : y&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Installing node modules with npm..&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;All NodeJS dependencies are successfully installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;--------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Would you like to install LunarVim&amp;#39;&lt;/span&gt;s Python dependencies?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;y&lt;span style="color:#f92672"&gt;]&lt;/span&gt;es or &lt;span style="color:#f92672"&gt;[&lt;/span&gt;n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;o &lt;span style="color:#f92672"&gt;(&lt;/span&gt;default: no&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying that pip is available..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/bin/python3: No module named ensurepip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing with pip..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Requirement already satisfied: pynvim in /usr/lib/python3/dist-packages &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.4.2&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;All Python dependencies are successfully installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Would you like to install LunarVim&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s Rust dependencies?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;y&lt;span style="color:#f92672"&gt;]&lt;/span&gt;es or &lt;span style="color:#f92672"&gt;[&lt;/span&gt;n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;o &lt;span style="color:#f92672"&gt;(&lt;/span&gt;default: no&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;All Rust dependencies are successfully installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里注意，除了NodeJS依赖需要安装，Python、Rust都已经安装好了，选择No就可以了。安装完成后可以使用命令打开&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#打开默认窗口&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lvim&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#打开指定文件&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#lvim install.sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#打开指定目录&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#lvim downloads&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;默认界面长这样子，可以搜索文件、搜索内容，打开文件、项目等。如果有出现文字、图标显示乱码，那么需要安装nerd font，参考上面的字体配置。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_163449.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="447px" data-flex-grow="186" height="161" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_163449-300x161.jpg" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215642.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="261px" data-flex-grow="109" height="275" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215642-300x275.jpg" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215610.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="260px" data-flex-grow="108" height="276" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215610-300x276.jpg" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;按下空格键就会出现引导界面&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_220013.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="517px" data-flex-grow="215" height="139" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_220013-300x139.jpg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;比如空格+e打开目录&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_163300.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="177px" data-flex-grow="74" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_163300-222x300.jpg" width="222"&gt;&lt;/a&gt;&lt;br&gt;&#10;空格+s搜索&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215913.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="517px" data-flex-grow="215" height="139" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215913-300x139.jpg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;空格+L打开LunarVim配置，比如keyMaps&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215539.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="258px" data-flex-grow="107" height="279" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215539-300x279.jpg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;剩下就是neovim、LuarVim的操作了，比如ctrl+h/ctrl+l的文件目录与代码窗口左右切换，空格+b+p/n/e/j在打开的文件里面切换、打开、关闭，alt+1/2/3打开下边、右边、弹出窗口里面打开终端&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215348.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="447px" data-flex-grow="186" height="161" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215348-300x161.jpg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215503.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="418px" data-flex-grow="174" height="172" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215503-300x172.jpg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215848.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="517px" data-flex-grow="215" height="139" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2022/11/IMG_20221120_215848-300x139.jpg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;如此便可以使用LunarVim写代码了。基于Neovim的编辑器还有&lt;a class="link" href="https://nvchad.com/" target="_blank" rel="noopener"&#10; &gt;NvChad&lt;/a&gt;，&lt;a class="link" href="https://spacevim.org/" target="_blank" rel="noopener"&#10; &gt;SpaceVim&lt;/a&gt;，也都非常强大，不过LunarVim默认配置了许多开箱即用的功能。另外，还可以使用&lt;a class="link" href="https://coder.com/docs/code-server/latest/termux" target="_blank" rel="noopener"&#10; &gt;code server&lt;/a&gt;，不过这个方案直接安装是不可以，需要借助&lt;a class="link" href="https://github.com/termux/proot-distro" target="_blank" rel="noopener"&#10; &gt;proot-distro&lt;/a&gt;安装其他Liunx才可以。如果Termux不能满足你的需求，可以使用proot-distro安装一个Linux来进一步模拟。如果觉得Termux好用的话，可以给它&lt;a class="link" href="https://termux.dev/en/donate.html" target="_blank" rel="noopener"&#10; &gt;捐款&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://wiki.termux.com/wiki/Main_Page" target="_blank" rel="noopener"&#10; &gt;Termux wiki&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.sqlsec.com/2018/05/termux.html" target="_blank" rel="noopener"&#10; &gt;Termux 高级终端安装使用配置教程&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>即时通信IRC服务Oragono</title><link>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1irc%E6%9C%8D%E5%8A%A1oragono/</link><pubDate>Wed, 18 Nov 2020 15:19:05 +0800</pubDate><guid>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1irc%E6%9C%8D%E5%8A%A1oragono/</guid><description>&lt;p&gt;前一篇讲了&lt;a class="link" href="https://courages.us/%e5%8d%b3%e6%97%b6%e9%80%9a%e4%bf%a1xmpp%e6%9c%8d%e5%8a%a1%e5%99%a8ejabberd-openfire/" target="_blank" rel="noopener"&#10; &gt;XMPP通信&lt;/a&gt;，还有一种比它还早的协议&lt;a class="link" href="https://zh.wikipedia.org/wiki/IRC" target="_blank" rel="noopener"&#10; &gt;IRC（Internet Relay Chat）&lt;/a&gt;，是一种简单的文本聊天协议，支持一对一聊天和群聊（频道）。通常IRC聊天只需要昵称而不需要密码（也可以使用密码），这与XMML不同，使得它可以作为公开的聊天频道，比如游戏直播平台Twitch就使用类似的功能来实现聊天。IRC同样有许多服务端，比如&lt;a class="link" href="https://www.inspircd.org/" target="_blank" rel="noopener"&#10; &gt;InspIRCd&lt;/a&gt;和客户端软件，比如&lt;a class="link" href="https://irssi.org/" target="_blank" rel="noopener"&#10; &gt;Irssi&lt;/a&gt;，也可以直接连接公开的IRC服务器，比如&lt;a class="link" href="https://freenode.net/" target="_blank" rel="noopener"&#10; &gt;Freenode&lt;/a&gt;。事实上IRC协议非常简单，只要能对相应的&lt;a class="link" href="https://ircv3.net/irc/" target="_blank" rel="noopener"&#10; &gt;命令&lt;/a&gt;作出响应就可以在各个客户端之间通信，因此有许多不同编程语言的服务端/客户端实现。&lt;a class="link" href="https://github.com/oragono/oragono" target="_blank" rel="noopener"&#10; &gt;Oragono&lt;/a&gt;便是IRC 服务器的Golang实现，支持&lt;a class="link" href="https://ircv3.net/" target="_blank" rel="noopener"&#10; &gt;IRCv3&lt;/a&gt;，支持SASL/LDAP认证，支持服务端保存消息历史记录。&lt;br&gt;&#10;Oragono运行很简单，克隆代码，编辑配置文件就可以了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHANGELOG.md     README           default.yaml     docs             languages        oragono          oragono.motd     traditional.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 cp default.yaml ircd.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ./oragono mkcerts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020/11/11 12:01:04 making self-signed certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020/11/11 12:01:04  making cert &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; :6697 listener&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020/11/11 12:01:04   Certificate created at fullchain.pem : privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHANGELOG.md     README           default.yaml     docs             fullchain.pem    ircd.yaml        languages        oragono          oragono.motd     privkey.pem      traditional.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  oragono24 ./oragono run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.320Z : info : server : oragono-2.4.0 starting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.320Z : info : server : Using config file : ircd.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.320Z : info : server : Using datastore : ircd.db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.344Z : info : server : Proxied IPs will be accepted from : localhost&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::1&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:6667, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on :6697, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on :8097, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : listeners : now listening on 127.0.0.1:6667, tls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tlsproxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, tor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false, websocket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;false.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:29.345Z : info : server : Server running&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:38.386Z : info : connect-ip : Client connecting: real IP 192.168.33.1, proxied IP &amp;lt;nil&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:38.439Z : info : accounts : client : * : logged into account : kiwi-n30&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:38.442Z : info : connect : Client connected &lt;span style="color:#f92672"&gt;[&lt;/span&gt;kiwi-n30&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;u:~u&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;r:https://kiwiirc.com/&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:40.955Z : info : connect-ip : Client connecting: real IP 192.168.33.1, proxied IP &amp;lt;nil&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:40.963Z : info : connect : Client connected &lt;span style="color:#f92672"&gt;[&lt;/span&gt;kiwi-n28&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;u:~u&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;r:https://kiwiirc.com/&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:56.198Z : info : connect-ip : Client connecting: real IP 192.168.33.1, proxied IP &amp;lt;nil&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-11-13T03:09:56.209Z : info : connect : Client connected &lt;span style="color:#f92672"&gt;[&lt;/span&gt;kiwi-n29&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;u:~u&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;r:https://kiwiirc.com/&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑ircd.yml，设置管理密码，启用一下WebSocket，保存历史消息到MySQL。opers/admin管理密码在认证管理员的时候使用的，可以使用命令oragono genpasswd生成。ircd.db用来保存注册用户，使用的并不是SQLite，而是Golang实现的一个嵌入式的内存Key/Value存储&lt;a class="link" href="https://github.com/tidwall/buntdb" target="_blank" rel="noopener"&#10; &gt;BuntDB&lt;/a&gt;，可以持久化到硬盘。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# network configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;network&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# name of the network&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;OragonoTest&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# server configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;server&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# server name&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;oragono.test&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# addresses to listen on&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;listeners&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The standard plaintext port for IRC is 6667. Allowing plaintext over the&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# public Internet poses serious security and privacy issues. Accordingly,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# we recommend using plaintext only on local (loopback) interfaces:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;127.0.0.1:6667&amp;#34;: &lt;/span&gt;&lt;span style="color:#75715e"&gt;# (loopback ipv4, localhost-only)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;[::1]:6667&amp;#34;: &lt;/span&gt; &lt;span style="color:#75715e"&gt;# (loopback ipv6, localhost-only)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# If you need to serve plaintext on public interfaces, comment out the above&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# two lines and uncomment the line below (which listens on all interfaces):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;:6667&amp;#34;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Alternately, if you have a TLS certificate issued by a recognized CA,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# you can configure port 6667 as an STS-only listener that only serves&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;redirects&amp;#34; to the TLS port, but doesn&amp;#39;t allow chat. See the manual&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# for details.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The standard SSL/TLS port for IRC is 6697. This will listen on all interfaces:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;:6697&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cert&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fullchain.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;key&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;privkey.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#39;proxy&amp;#39; should typically be false. It&amp;#39;s only for Kubernetes-style load&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# balancing that does not terminate TLS, but sends an initial PROXY line&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# in plaintext.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Example of a Unix domain socket for proxying:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;/tmp/oragono_sock&amp;#34;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Example of a Tor listener: any connection that comes in on this listener will&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# be considered a Tor connection. It is strongly recommended that this listener&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# *not* be on a public interface --- it should be on 127.0.0.0/8 or unix domain:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;/hidden_service_sockets/oragono_tor_sock&amp;#34;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# tor: true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Example of a WebSocket listener:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;:8097&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;websocket&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cert&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fullchain.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;key&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;privkey.pem&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ircd operators&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;opers&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# operator named &amp;#39;admin&amp;#39;; log in with /OPER admin [password]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;admin&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# which capabilities this oper has access to&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;class&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;server-admin&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# custom whois line&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;whois-line&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;is a server admin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# custom hostname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;vhost&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;staff&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# normally, operator status is visible to unprivileged users in WHO and WHOIS&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# responses. this can be disabled with &amp;#39;hidden&amp;#39;. (&amp;#39;hidden&amp;#39; also causes the&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# &amp;#39;vhost&amp;#39; line above to be ignored.)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;hidden&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# modes are modes to auto-set upon opering-up. uncomment this to automatically&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# enable snomasks (&amp;#34;server notification masks&amp;#34; that alert you to server events;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# see `/quote help snomasks` while opered-up for more information):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#modes: +is acjknoqtuxv&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# operators can be authenticated either by password (with the /OPER command),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# or by certificate fingerprint, or both. if a password hash is set, then a&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# password is required to oper up (e.g., /OPER dan mypassword). to generate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# the hash, use `oragono genpasswd`.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;password&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$2a$04$I2Yhr7UF4p3iyEZcKTPJgukLA9mm00B1wQgicJvGZP/gf0u0tbQQy&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# datastore configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;datastore&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# path to the datastore&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ircd.db&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# if the database schema requires an upgrade, `autoupgrade` will attempt to&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# perform it automatically on startup. the database will be backed&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# up, and if the upgrade fails, the original database will be restored.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;autoupgrade&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# connection information for MySQL (currently only used for persistent history):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mysql&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;host&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3306&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# if socket-path is set, it will be used instead of host:port&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#socket-path: &amp;#34;/var/run/mysqld/mysqld.sock&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;user&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;password&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;history-database&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;oragono_history&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;timeout&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;IRC服务端设置好了，使用客户端连上去就可以聊天了。IRC协议类似HTTP协议，服务器地址类似irc://irc.freenode.net，但是也可以使用web来连接，前面配置了监听来自8097端口的websocket请求。这里使用web的IRC客户端&lt;a class="link" href="https://kiwiirc.com/" target="_blank" rel="noopener"&#10; &gt;Kiwi IRC&lt;/a&gt;，这是Vue实现的一个web客户端，各个组件之间通过触发/订阅Vue实例状态/事件变化进行通信，支持自定义组件/中间件，这也是Freenode使用的客户端。Kiwiirc主要聚焦连接和消息的处理，比如websocket连接/发送/监听，消息的格式化/通知/声音/状态。它能够连接websocket的IRC服务器，甚至还提供在线&lt;a class="link" href="https://kiwiirc.com/clientbuilder/#/" target="_blank" rel="noopener"&#10; &gt;生成器&lt;/a&gt;，只需要添加websocket url就好了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;windowTitle&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Kiwi IRC with Oragono Test&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;startupScreen&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;welcome&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;kiwiServer&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;http://oragono.test&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;restricted&amp;#34;&lt;/span&gt;: false,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;theme&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;themes&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/default&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Dark&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/dark&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Coffee&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/coffee&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;GrayFox&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/grayfox&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Nightswatch&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/nightswatch&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Osprey&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/osprey&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Radioactive&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/radioactive&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Sky&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/sky&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Elite&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/themes/elite&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;startupOptions&amp;#34;&lt;/span&gt; : &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;websocket&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;wss://127.0.0.1:8097&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;channel&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;#kiwiirc-default&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;nick&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;kiwi-n?&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;embedly&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;plugins&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;customise&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;static/plugins/customise.html&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行登录后的效果&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_action.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="310px" data-flex-grow="129" height="232" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_action-300x232.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_auth.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="566px" data-flex-grow="236" height="127" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_auth-300x127.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_auth_no.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="660px" data-flex-grow="275" height="109" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_auth_no-300x109.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_channel.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="960px" data-flex-grow="400" height="75" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_channel-300x75.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_channel_register.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="406px" data-flex-grow="169" height="177" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_channel_register-300x177.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_invite.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="293px" data-flex-grow="122" height="245" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_invite-300x245.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_join_history.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="431px" data-flex-grow="179" height="167" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_join_history-300x167.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_join_self.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="452px" data-flex-grow="188" height="159" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_join_self-300x159.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_login.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="566px" data-flex-grow="236" height="127" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_login-300x127.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_oper.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="231px" data-flex-grow="96" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_oper-289x300.png" width="289"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/kiwi_preload.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="489px" data-flex-grow="204" height="147" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/kiwi_preload-300x147.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;其实IRC是基于TCP连接的文本交互的，也可以使用telnet来模拟&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ telnet 127.0.0.1 &lt;span style="color:#ae81ff"&gt;6667&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Trying 127.0.0.1...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connected to localhost.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Escape character is &lt;span style="color:#e6db74"&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CAP LS &lt;span style="color:#ae81ff"&gt;302&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:oragono.test CAP * LS * :account-notify account-tag away-notify batch cap-notify chghost draft/channel-rename draft/chathistory draft/event-playback draft/languages&lt;span style="color:#f92672"&gt;=&lt;/span&gt;16,en,~bs,~de,~el,~en-AU,~es,~fi,~fr-FR,~it,~nl,~no,~pl,~pt-BR,~ro,~tr-TR,~zh-CN draft/multiline&lt;span style="color:#f92672"&gt;=&lt;/span&gt;max-bytes&lt;span style="color:#f92672"&gt;=&lt;/span&gt;4096,max-lines&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; draft/register&lt;span style="color:#f92672"&gt;=&lt;/span&gt;before-connect draft/relaymsg&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/ draft/resume-0.5 echo-message extended-join invite-notify labeled-response message-tags multi-prefix oragono.io/nope sasl&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PLAIN,EXTERNAL server-time setname&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:oragono.test CAP * LS :userhost-in-names znc.in/playback znc.in/self-message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NICK kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;USER kiwi-n26 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; * https://kiwiirc.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CAP REQ :account-notify account-tag away-notify batch cap-notify draft/chathistory extended-join invite-notify message-tags multi-prefix server-time userhost-in-names znc.in/self-message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:02.201Z :oragono.test CAP * ACK :account-notify account-tag away-notify batch cap-notify draft/chathistory extended-join invite-notify message-tags multi-prefix server-time userhost-in-names znc.in/self-message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CAP END&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;001&lt;/span&gt; kiwi-n26 :Welcome to the Internet Relay Network kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;002&lt;/span&gt; kiwi-n26 :Your host is oragono.test, running version oragono-2.4.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;003&lt;/span&gt; kiwi-n26 :This server was created Fri, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; Nov &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 00:35:48 UTC&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;004&lt;/span&gt; kiwi-n26 oragono.test oragono-2.4.0 BERTZios CEIMRUabehiklmnoqstuv Iabehkloqv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;005&lt;/span&gt; kiwi-n26 AWAYLEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;390&lt;/span&gt; BOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;B CASEMAPPING&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ascii CHANLIMIT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;#:100 CHANMODES=Ibe,k,l,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m INVEX KICKLEN=390 MAXLIST=beI:60 :are supported by this server&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;005&lt;/span&gt; kiwi-n26 MAXTARGETS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; MODES MONITOR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; NETWORK&lt;span style="color:#f92672"&gt;=&lt;/span&gt;OragonoTest NICKLEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; PREFIX&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;qaohv&lt;span style="color:#f92672"&gt;)&lt;/span&gt;~&amp;amp;@%+ STATUSMSG&lt;span style="color:#f92672"&gt;=&lt;/span&gt;~&amp;amp;@%+ TARGMAX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;390&lt;/span&gt; UTF8MAPPING&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rfc8265 WHOX draft/CHATHISTORY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; :are supported by this server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;251&lt;/span&gt; kiwi-n26 :There are &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; users and &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; invisible on &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; server&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;252&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :IRC Operators online&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;253&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :unregistered connections&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;254&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; :channels formed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt; kiwi-n26 :I have &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; clients and &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; servers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;265&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; :Current local users 4, max &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;266&lt;/span&gt; kiwi-n26 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; :Current global users 4, max &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;375&lt;/span&gt; kiwi-n26 :- oragono.test Message of the day -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▄▄▄ ▄▄▄· ▄▄ • ▐ ▄&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▪ ▀▄ █·▐█ ▀█ ▐█ ▀ ▪▪ •█▌▐█▪&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▄█▀▄ ▐▀▀▄ ▄█▀▀█ ▄█ ▀█▄ ▄█▀▄▪▐█▐▐▌ ▄█▀▄&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▐█▌.▐▌▐█•█▌▐█ ▪▐▌▐█▄▪▐█▐█▌ ▐▌██▐█▌▐█▌.▐▌&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- ▀█▄▀▪.▀ ▀ ▀ ▀ ·▀▀▀▀ ▀█▄▀ ▀▀ █▪ ▀█▄▀▪&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- This is the default Oragono MOTD.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- If motd-formatting is enabled in the config file, you can use the dollarsign character to&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- create special formatting such as bold, italics and color codes.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- For example, here are a few formatted lines &lt;span style="color:#f92672"&gt;(&lt;/span&gt;enable motd-formatting to see these in action&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is bold text.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is italics text.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is 4red and 2blue text.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is 4,12red text with a light blue background.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- - this is a normal escaped dollarsign: $&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- And now a few fun colour charts!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 1,0 &lt;span style="color:#ae81ff"&gt;00&lt;/span&gt; 0,1 &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; 0,2 &lt;span style="color:#ae81ff"&gt;02&lt;/span&gt; 0,3 &lt;span style="color:#ae81ff"&gt;03&lt;/span&gt; 1,4 &lt;span style="color:#ae81ff"&gt;04&lt;/span&gt; 0,5 &lt;span style="color:#ae81ff"&gt;05&lt;/span&gt; 0,6 &lt;span style="color:#ae81ff"&gt;06&lt;/span&gt; 1,7 &lt;span style="color:#ae81ff"&gt;07&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 1,8 &lt;span style="color:#ae81ff"&gt;08&lt;/span&gt; 1,9 &lt;span style="color:#ae81ff"&gt;09&lt;/span&gt; 0,10 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 1,11 &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; 0,12 &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; 1,13 &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; 1,14 &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 1,15 &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,16 &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; 0,17 &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; 0,18 &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt; 0,19 &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; 0,20 &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; 0,21 &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt; 0,22 &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; 0,23 &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; 0,24 &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; 0,25 &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt; 0,26 &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; 0,27 &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,28 &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; 0,29 &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 0,30 &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; 0,31 &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; 0,32 &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; 0,33 &lt;span style="color:#ae81ff"&gt;33&lt;/span&gt; 0,34 &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; 0,35 &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; 0,36 &lt;span style="color:#ae81ff"&gt;36&lt;/span&gt; 0,37 &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; 0,38 &lt;span style="color:#ae81ff"&gt;38&lt;/span&gt; 0,39 &lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,40 &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt; 0,41 &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; 0,42 &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt; 0,43 &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt; 0,44 &lt;span style="color:#ae81ff"&gt;44&lt;/span&gt; 0,45 &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt; 0,46 &lt;span style="color:#ae81ff"&gt;46&lt;/span&gt; 0,47 &lt;span style="color:#ae81ff"&gt;47&lt;/span&gt; 0,48 &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt; 0,49 &lt;span style="color:#ae81ff"&gt;49&lt;/span&gt; 0,50 &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt; 0,51 &lt;span style="color:#ae81ff"&gt;51&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,52 &lt;span style="color:#ae81ff"&gt;52&lt;/span&gt; 0,53 &lt;span style="color:#ae81ff"&gt;53&lt;/span&gt; 1,54 &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt; 1,55 &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt; 1,56 &lt;span style="color:#ae81ff"&gt;56&lt;/span&gt; 1,57 &lt;span style="color:#ae81ff"&gt;57&lt;/span&gt; 1,58 &lt;span style="color:#ae81ff"&gt;58&lt;/span&gt; 0,59 &lt;span style="color:#ae81ff"&gt;59&lt;/span&gt; 0,60 &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt; 0,61 &lt;span style="color:#ae81ff"&gt;61&lt;/span&gt; 0,62 &lt;span style="color:#ae81ff"&gt;62&lt;/span&gt; 0,63 &lt;span style="color:#ae81ff"&gt;63&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,64 &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; 1,65 &lt;span style="color:#ae81ff"&gt;65&lt;/span&gt; 1,66 &lt;span style="color:#ae81ff"&gt;66&lt;/span&gt; 1,67 &lt;span style="color:#ae81ff"&gt;67&lt;/span&gt; 1,68 &lt;span style="color:#ae81ff"&gt;68&lt;/span&gt; 1,69 &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; 1,70 &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt; 1,71 &lt;span style="color:#ae81ff"&gt;71&lt;/span&gt; 0,72 &lt;span style="color:#ae81ff"&gt;72&lt;/span&gt; 0,73 &lt;span style="color:#ae81ff"&gt;73&lt;/span&gt; 0,74 &lt;span style="color:#ae81ff"&gt;74&lt;/span&gt; 0,75 &lt;span style="color:#ae81ff"&gt;75&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 1,76 &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt; 1,77 &lt;span style="color:#ae81ff"&gt;77&lt;/span&gt; 1,78 &lt;span style="color:#ae81ff"&gt;78&lt;/span&gt; 1,79 &lt;span style="color:#ae81ff"&gt;79&lt;/span&gt; 1,80 &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; 1,81 &lt;span style="color:#ae81ff"&gt;81&lt;/span&gt; 1,82 &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt; 1,83 &lt;span style="color:#ae81ff"&gt;83&lt;/span&gt; 1,84 &lt;span style="color:#ae81ff"&gt;84&lt;/span&gt; 1,85 &lt;span style="color:#ae81ff"&gt;85&lt;/span&gt; 1,86 &lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; 1,87 &lt;span style="color:#ae81ff"&gt;87&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- 0,88 &lt;span style="color:#ae81ff"&gt;88&lt;/span&gt; 0,89 &lt;span style="color:#ae81ff"&gt;89&lt;/span&gt; 0,90 &lt;span style="color:#ae81ff"&gt;90&lt;/span&gt; 0,91 &lt;span style="color:#ae81ff"&gt;91&lt;/span&gt; 0,92 &lt;span style="color:#ae81ff"&gt;92&lt;/span&gt; 0,93 &lt;span style="color:#ae81ff"&gt;93&lt;/span&gt; 0,94 &lt;span style="color:#ae81ff"&gt;94&lt;/span&gt; 0,95 &lt;span style="color:#ae81ff"&gt;95&lt;/span&gt; 1,96 &lt;span style="color:#ae81ff"&gt;96&lt;/span&gt; 1,97 &lt;span style="color:#ae81ff"&gt;97&lt;/span&gt; 1,98 &lt;span style="color:#ae81ff"&gt;98&lt;/span&gt; 99,99 &lt;span style="color:#ae81ff"&gt;99&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :-&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;372&lt;/span&gt; kiwi-n26 :- For more information on using these, see MOTDFORMATTING.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.714Z :oragono.test &lt;span style="color:#ae81ff"&gt;376&lt;/span&gt; kiwi-n26 :End of MOTD command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:07.715Z :oragono.test &lt;span style="color:#ae81ff"&gt;221&lt;/span&gt; kiwi-n26 +Zi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WHO kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:15.649Z :oragono.test &lt;span style="color:#ae81ff"&gt;352&lt;/span&gt; kiwi-n26 * ~u gcjc79gmtbe42.irc oragono.test kiwi-n26 H :0 https://kiwiirc.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:15.649Z :oragono.test &lt;span style="color:#ae81ff"&gt;315&lt;/span&gt; kiwi-n26 kiwi-n26!*@* :End of WHO list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;JOIN &lt;span style="color:#75715e"&gt;#kiwiirc-default&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@msgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;bidkvpja5njjtgchub8u65pxgn;time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:26.706Z :kiwi-n26!~u@gcjc79gmtbe42.irc JOIN &lt;span style="color:#75715e"&gt;#kiwiirc-default * https://kiwiirc.com/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:26.706Z :oragono.test &lt;span style="color:#ae81ff"&gt;353&lt;/span&gt; kiwi-n26 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#75715e"&gt;#kiwiirc-default :@kiwi-n28!~u@5g96q93tqw3vn.irc kiwi-n30!~u@5g96q93tqw3vn.irc kiwi-n29!~u@5g96q93tqw3vn.irc kiwi-n26!~u@gcjc79gmtbe42.irc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:26.706Z :oragono.test &lt;span style="color:#ae81ff"&gt;366&lt;/span&gt; kiwi-n26 &lt;span style="color:#75715e"&gt;#kiwiirc-default :End of NAMES list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;JOIN &lt;span style="color:#75715e"&gt;#ops&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@msgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hftqmpu4ieyjybx9bbgf4vpbia;time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:32.145Z :kiwi-n26!~u@gcjc79gmtbe42.irc JOIN &lt;span style="color:#75715e"&gt;#ops * https://kiwiirc.com/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:32.145Z :oragono.test &lt;span style="color:#ae81ff"&gt;353&lt;/span&gt; kiwi-n26 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#75715e"&gt;#ops :@kiwi-n28!~u@5g96q93tqw3vn.irc kiwi-n30!~u@5g96q93tqw3vn.irc kiwi-n29!~u@5g96q93tqw3vn.irc kiwi-n26!~u@gcjc79gmtbe42.irc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:55:32.145Z :oragono.test &lt;span style="color:#ae81ff"&gt;366&lt;/span&gt; kiwi-n26 &lt;span style="color:#75715e"&gt;#ops :End of NAMES list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PRIVMSG &lt;span style="color:#75715e"&gt;#ops hello&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PRIVMSG &lt;span style="color:#75715e"&gt;#ops :kiwi-n28 good morning&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PRIVMSG kiwi-n28 &lt;span style="color:#f92672"&gt;=&lt;/span&gt;D&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PING kiwitime-1605232555315&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:57:14.150Z :oragono.test PONG oragono.test kiwitime-1605232555315&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHATHISTORY BEFORE kiwi-n28 * &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:57:38.462Z :oragono.test BATCH +1 chathistory kiwi-n28&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@msgid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rqdbvmytzppssc5ymp7ffhmkga;time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:56:05.705Z;batch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; :kiwi-n26!~u@gcjc79gmtbe42.irc PRIVMSG kiwi-n28 :&lt;span style="color:#f92672"&gt;=&lt;/span&gt;D&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:57:38.462Z :oragono.test BATCH -1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2020-11-13T01:59:08.466Z PING kiwi-n26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:kiwi-n26!~u@gcjc79gmtbe42.irc QUIT :Ping timeout: 2m30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR :Ping timeout: 2m30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection closed by foreign host.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到这些消息都带有一定的格式，客户端根据特地的格式解析就可以个性化显示来。带有符号@/：前缀的消息都是服务器推送下来的消息，反之都是客户端请求的消息。“CAP LS 302”即协商会话协议版本，随即用命令“NICK ”设置昵称（登录名），和“USER 0 * ”设置该昵称显示的用户名，最后以“CAP END”结束协商，开始会话。服务端推送过来的消息格式为时间戳+服务器+响应码+接受者昵称+消息内容，即“@time=2020-11-13T01:55:07.714Z :oragono.test 001 :Welcome to the Internet Relay Network ”，001代表欢迎信息，具体响应码可以参考&lt;a class="link" href="https://tools.ietf.org/html/rfc2812#section-5.2" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。客户端发送消息则直接发送，比如使用“JOIN #channel”加入某个频道，服务器会向该频道里的每个人广播对JOIN应的消息“@msgid=hftqmpu4ieyjybx9bbgf4vpbia;time=2020-11-13T01:55:32.145Z :@gcjc79gmtbe42.irc JOIN #channel * ”并向操作者推送频道用户列表“@time=2020-11-13T01:55:32.145Z :oragono.test 353 = #channel :@!~&lt;a class="link" href="mailto:u@5g96q93tqw3vn.irc" &gt;u@5g96q93tqw3vn.irc&lt;/a&gt; !~&lt;a class="link" href="mailto:u@5g96q93tqw3vn.irc" &gt;u@5g96q93tqw3vn.irc&lt;/a&gt; !~&lt;a class="link" href="mailto:u@5g96q93tqw3vn.irc" &gt;u@5g96q93tqw3vn.irc&lt;/a&gt;&lt;br&gt;&#10;”。Twitch则在消息的基础上加入了其他格式化控制，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@badge-info&lt;span style="color:#f92672"&gt;=&lt;/span&gt;;badges&lt;span style="color:#f92672"&gt;=&lt;/span&gt;premium/1;client-nonce&lt;span style="color:#f92672"&gt;=&lt;/span&gt;2f70a1efd6f84523d0f180cc44f76c61;color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#75715e"&gt;#B22222;display-name=Khodeine;emotes=58765:9-19;flags=;id=50d8790f-c474-42a8-b873-2d5e8008bd52;mod=0;room-id=30220059;subscriber=0;tmi-sent-ts=1605279854692;turbo=0;user-id=49980352;user-type= :khodeine!khodeine@khodeine.tmi.twitch.tv PRIVMSG #esl_sc2 :the scvs NotLikeThis&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会显示以一定的颜色/图标显示用户名/消息。空闲状态下IRC服务端与客户端需要维持心跳信息，比如“PING kiwitime-1605232555315”和“time=2020-11-13T01:57:14.150Z :oragono.test PONG oragono.test kiwitime-1605232555315”，否则连接会被关闭。一些常用的命令，可以看出IRC交互非常简单，&lt;a class="link" href="https://en.wikipedia.org/wiki/IRC_services" target="_blank" rel="noopener"&#10; &gt;IRC核心组件&lt;/a&gt;也不多。使用“@+dratf/typing=active TAGMSG ”显示输入状态，借助&lt;a class="link" href="https://tools.ietf.org/id/draft-oakley-irc-ctcp-01.html" target="_blank" rel="noopener"&#10; &gt;CTCP&lt;/a&gt;协议甚至可以点对点发送文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使用password注册当前nickname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/NS REGISTER &amp;lt;your password&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#注册一个频道&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/CS REGISTER &lt;span style="color:#75715e"&gt;#channelname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/CS REGISTER &lt;span style="color:#75715e"&gt;#channe&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#要去某人加入频道&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/INVITE nickname &lt;span style="color:#75715e"&gt;#channel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#给予某个用户频道管理权限&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/mode +o nickname&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#认证成为管理员&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/OPER admin &amp;lt;admin passowrd&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#在频道发送消息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/PRIVMSG &lt;span style="color:#75715e"&gt;#channe hello&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#给频道某人发送消息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/PRIVMSG &lt;span style="color:#75715e"&gt;#channe :&amp;lt;nick&amp;gt; good morning&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#给频道某人发送消息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/INVITE &amp;lt;nick&amp;gt; &lt;span style="color:#75715e"&gt;#channe&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使用密码登录&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTHENTICATE PLAIN&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTHENTICATE +&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTHENTICATE a2l3aS1uMzAAa2l3aS1uMzAAMTAyMDMwNDA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="https://thelounge.chat/" target="_blank" rel="noopener"&#10; &gt;Thelounge&lt;/a&gt;是另外一个Vue实现的web的IRC客户端，同样支持websocket。它还用express实现了服务端，支持额外的密码/LDAP登录，即先认证通过才能连接IRC服务器，它本身也可以作为一个服务代理网关，为用户提供永远在线服务/消息存储-如果一个IRC用户不在线是不能够给它发送消息的，这一点也跟XMPP不一样。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/lounge_join.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="480px" data-flex-grow="200" height="150" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/lounge_join-300x150.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/lounge_send.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="431px" data-flex-grow="179" height="167" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/lounge_send-300x167.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Kiwiirc和Thelounge的设计实现良好，可以作为web chat实现的参考，比如在线客服/销售。比较两个web的IRC客户端发现，他们使用的websocket库并不一样。Kiwiirc使用的是&lt;a class="link" href="https://github.com/sockjs/sockjs-client" target="_blank" rel="noopener"&#10; &gt;sockjs-client&lt;/a&gt;，一个类似websocket的JavaScript网络连接库，支持不同浏览器，能够跨域名通信，在浏览器不支持websocket的情况下退化为&lt;a class="link" href="https://www.pubnub.com/blog/http-long-polling/" target="_blank" rel="noopener"&#10; &gt;polling&lt;/a&gt;（需要&lt;a class="link" href="https://github.com/sockjs/sockjs-node" target="_blank" rel="noopener"&#10; &gt;服务端&lt;/a&gt;配合）。而Thelounge使用的是&lt;a class="link" href="https://github.com/socketio/socket.io" target="_blank" rel="noopener"&#10; &gt;socket.io&lt;/a&gt;。Socket.IO由Engine.IO发展而来，致力于为web提供实时通信能力。Socket.IO并不是WebSocket的一个实现，只是提供了类似的连接能力，需要服务端配合。两个连接库在浏览器支持websocket的情况下都可以直接与websocket服务端通信（不需要对应的库）。Kiwiirc还提供了irc-framework开发库，可以快速搭建一个IRC客户端，比如IRC Bot。至今仍然存在着许多&lt;a class="link" href="https://en.wikipedia.org/wiki/IRC_bot" target="_blank" rel="noopener"&#10; &gt;IRC聊天机器人&lt;/a&gt;，为用户提供方便/服务器报警。Twitch一个用户加入频道时甚至能收到广告！&lt;/p&gt;&#10;&lt;p&gt;Websocket提供了与其他socket一样的能力，能够持续连接和双向通讯，甚至可以服用80/443端口（nginx支持101协议升级）。它不止可以使用在web上，也可以使用在非web上面，因为能够穿透防火墙，对树莓派的远程链接支持。传统的web应用都是一应一答，这节省的服务器/客户端的资源能够不需要持续请求的话。而对于有些应用而言，比如消息通知，希望是能够持续从服务器推送的，websocket增强了它的能力，在这之前都是long polling（所以才有那些包装库）。&lt;br&gt;&#10;Http协议在tcp基础上实现，请求头里面带有host、cookie，url里面带有路径等，这样后端能够识别、路由、分发请求。而tcp并没有这些，websocket必须自己实现类似的路由分发/调用，可以在连接建立初期，鉴别授权（可以在url上面带参数token/jwt/security key），对于后续消息的应答可以在url上面指定，也可以在事件上面指定。这样实现出来似乎与http差不多，仍然有event对应route，但却可以持续交互。&lt;br&gt;&#10;再观察IRC协议也不过是对各个命令的应答，其实也跟经典web MVC差不多-使用URL映射对应的controller/action。IRC每个会话都是一个队列，join #channel命令即订阅消息，part #channel命令则是取消订阅。再看Rabbitmq消息队列，实现了exchange，route，queue，channel，topic等，然后是持续的消费/推送，与前面所诉差不多，这样子看IRC也是个消息服务器。IRC实现简单，通过扩展支持的命令，也能够与内部/外部系统结合，快速搭建一个即时消息平台。&lt;br&gt;&#10;再看邮件服务，其实也是消息服务，也有一对一/群发消息/历史消息，甚至能够给不认识（不在线）的人发送邮件！而邮件服务至今流行，在许多平台，不论服务器还是手机都自带，不需要额外安装软件。&lt;a class="link" href="https://slack.com/intl/en-cn/features" target="_blank" rel="noopener"&#10; &gt;Slack&lt;/a&gt;的产品宣传即对比了自己相对邮件服务的优势。其实手机默认带的电话和短信功能是基于硬件模块的在线功能。&lt;br&gt;&#10;相比Ejabberd/Openfire，IRC服务器的部署简单许多，甚至可以部署在树莓派上！&lt;/p&gt;&#10;&lt;p&gt;参考连接：&lt;br&gt;&#10;&lt;a class="link" href="http://IRC%20bot" target="_blank" rel="noopener"&#10; &gt;IRC Bot&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://developer.ibm.com/zh/technologies/messaging/articles/os-cn-rabbit-mq/" target="_blank" rel="noopener"&#10; &gt;基于 RabbitMQ 的实时消息推送&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>即时通信XMPP服务器ejabberd/Openfire</title><link>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1xmpp%E6%9C%8D%E5%8A%A1%E5%99%A8ejabberd-openfire/</link><pubDate>Thu, 05 Nov 2020 17:14:06 +0800</pubDate><guid>https://courages.us/%E5%8D%B3%E6%97%B6%E9%80%9A%E4%BF%A1xmpp%E6%9C%8D%E5%8A%A1%E5%99%A8ejabberd-openfire/</guid><description>&lt;p&gt;即时通信的需求，不仅在公共互联网上，比如微信、QQ，也在企业的内部网络，特别是与内部系统的整合，比如OA、客服系统。&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%8F%AF%E6%89%A9%E5%B1%95%E6%B6%88%E6%81%AF%E4%B8%8E%E5%AD%98%E5%9C%A8%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;XMPP&lt;/a&gt;，也叫扩展消息与存在协议，是一种以XML为基础的开放式即时通信协议。&lt;a class="link" href="https://xmpp.org/" target="_blank" rel="noopener"&#10; &gt;XMPP&lt;/a&gt;不但能够用来做消息通信（单聊/群聊/订阅），也可以做语音通信。XMPP甚至支持多个服务器之间互相连接，互相通信，早期Gtalk就能够与其他XMPP服务器通信。采用XMPP来开发的好处是，已经有大量的开源服务器（ejabberd、Openfire）和客户端（Spark/Smack/converse.js/XMPPFramework）实现，能够快速搭建。&lt;br&gt;&#10;&lt;a class="link" href="https://www.ejabberd.im/" target="_blank" rel="noopener"&#10; &gt;Ejabberd&lt;/a&gt;则是ProcessOne出品的，基于Erlang开发的XMPP/MQTT/SIP服务器，内置了WebSocket/文件上传支持，提供更加丰富的&lt;a class="link" href="https://docs.ejabberd.im/developer/ejabberd-api/" target="_blank" rel="noopener"&#10; &gt;REST API&lt;/a&gt;。在CentOS64下面安装Ejabberd，会安装到/etc/init.d/ejabberd，直接service start ejabberd就好了，可以使用&lt;a class="link" href="https://github.com/processone/docker-ejabberd" target="_blank" rel="noopener"&#10; &gt;docker&lt;/a&gt;快速启用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# wget https://static.process-one.net/ejabberd/downloads/20.04/ejabberd-20.04-0.x86_64.rpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--2020-10-29 08:26:16--  https://static.process-one.net/ejabberd/downloads/20.04/ejabberd-20.04-0.x86_64.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Resolving static.process-one.net... 13.226.36.69, 13.226.36.105, 13.226.36.34, ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connecting to static.process-one.net|13.226.36.69|:443... connected.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP request sent, awaiting response... &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Length: &lt;span style="color:#ae81ff"&gt;18713774&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;18M&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;application/x-rpm&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Saving to: “ejabberd-20.04-0.x86_64.rpm”&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;100%&lt;span style="color:#f92672"&gt;[====================================================================================================================================================================================================================================&lt;/span&gt;&amp;gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 18,713,774  2.84M/s   in 9.1s    &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-29 08:26:27 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.96 MB/s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; - “ejabberd-20.04-0.x86_64.rpm” saved &lt;span style="color:#f92672"&gt;[&lt;/span&gt;18713774/18713774&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# yum localinstall ejabberd-20.04-0.x86_64.rpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded plugins: fastestmirror&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Setting up Local Package Process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Examining ejabberd-20.04-0.x86_64.rpm: ejabberd-20.04-0.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Marking ejabberd-20.04-0.x86_64.rpm to be installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loading mirror speeds from cached hostfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * base: mirrors.163.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * epel: mirror.math.princeton.edu&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * extras: mirrors.cn99.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * updates: mirrors.cn99.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * webtatic: uk.repo.webtatic.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable/signature                                                                                                                                                                                                                               |  &lt;span style="color:#ae81ff"&gt;819&lt;/span&gt; B     00:00     &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable/signature                                                                                                                                                                                                                               |  &lt;span style="color:#ae81ff"&gt;951&lt;/span&gt; B     00:00 ... &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable-source/signature                                                                                                                                                                                                                        |  &lt;span style="color:#ae81ff"&gt;819&lt;/span&gt; B     00:00     &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon_stable-source/signature                                                                                                                                                                                                                        |  &lt;span style="color:#ae81ff"&gt;951&lt;/span&gt; B     00:00 ... &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Resolving Dependencies&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--&amp;gt; Running transaction check&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---&amp;gt; Package ejabberd.x86_64 0:20.04-0 will be installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--&amp;gt; Finished Dependency Resolution&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dependencies Resolved&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==============================================================================================================================================================================================================================================================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Package                                                       Arch                                                        Version                                                        Repository                                                                     Size&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==============================================================================================================================================================================================================================================================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ejabberd                                                      x86_64                                                      20.04-0                                                        /ejabberd-20.04-0.x86_64                                                       &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transaction Summary&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==============================================================================================================================================================================================================================================================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Install       &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; Package&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Total size: &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installed size: &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Is this ok &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/N&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Downloading Packages:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Running rpm_check_debug&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Running Transaction Test&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transaction Test Succeeded&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Running Transaction&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  Installing : ejabberd-20.04-0.x86_64                                                                                                                                                                                                                                    1/1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  Verifying  : ejabberd-20.04-0.x86_64                                                                                                                                                                                                                                    1/1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installed:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  ejabberd.x86_64 0:20.04-0                                                                                                                                                                                                                                                   &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Complete!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls  /etc/init.d/ejabberd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/etc/init.d/ejabberd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 tmp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls -la /opt/ejabberd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; root     root     &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 database&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-r--------  &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ejabberd ejabberd   &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 00:00 .erlang.cookie&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x  &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; ejabberd ejabberd &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 08:27 logs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# service ejabberd start&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting ejabberd...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 sql&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ps aux | grep ejabberd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ejabberd 10097  0.2  7.9 &lt;span style="color:#ae81ff"&gt;1817344&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;48144&lt;/span&gt; ?       Sl   08:51   0:04 /opt/ejabberd-20.04/bin/beam.smp -K true -P &lt;span style="color:#ae81ff"&gt;250000&lt;/span&gt; -- -root /opt/ejabberd-20.04 -progname /opt/ejabberd-20.04/bin/erl -- -home /opt/ejabberd -- -sname ejabberd@localhost -smp enable -mnesia dir &lt;span style="color:#e6db74"&gt;&amp;#34;/opt/ejabberd/database/ejabberd@localhost&amp;#34;&lt;/span&gt; -ejabberd log_rate_limit &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; log_rotate_size &lt;span style="color:#ae81ff"&gt;10485760&lt;/span&gt; log_rotate_count &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; log_rotate_date &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; -s ejabberd -noshell -noinput&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ejabberd 10105  0.0  0.0   &lt;span style="color:#ae81ff"&gt;4060&lt;/span&gt;   &lt;span style="color:#ae81ff"&gt;496&lt;/span&gt; ?        Ss   08:51   0:00 erl_child_setup &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ejabberd 10186  0.0  0.0   &lt;span style="color:#ae81ff"&gt;4052&lt;/span&gt;   &lt;span style="color:#ae81ff"&gt;572&lt;/span&gt; ?        Ss   08:51   0:00 /opt/ejabberd-20.04/lib/os_mon-2.4.7/priv/bin/memsup&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root     11215  0.0  0.1 &lt;span style="color:#ae81ff"&gt;103324&lt;/span&gt;   &lt;span style="color:#ae81ff"&gt;892&lt;/span&gt; pts/4    S+   09:16   0:00 grep ejabberd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# netstat -apn | grep beam&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:7777              0.0.0.0:*                   LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:37617               0.0.0.0:*                   LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:15672               0.0.0.0:*                   LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:55672               0.0.0.0:*                   LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0.0.0.0:43674               0.0.0.0:*                   LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:44055             127.0.0.1:4369              ESTABLISHED 1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:35415             127.0.0.1:4369              ESTABLISHED 10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5280                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5443                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5222                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5672                     :::*                        LISTEN      1599/beam           &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::5269                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp        0      &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; :::1883                     :::*                        LISTEN      10097/beam.smp      &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unix  3      &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;         STREAM     CONNECTED     &lt;span style="color:#ae81ff"&gt;1637533&lt;/span&gt; 10097/beam.smp   &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ejabberd自带Erlang的数据库服务Mnesia，但有一些限制建议使用第三方的比如MySQL，这样也方便第三方交互（比如认证Token）。初始化的SQL脚本在/opt/ejabberd-20.04/lib/ejabberd-20.04/priv/sql，如果只是支持单个domain的话使用mysql.sql就可以了，多domain支持使用mysql.new.sql&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 sql&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lite.new.sql  lite.sql  mssql.sql  mysql.new.sql  mysql.sql  pg.new.sql  pg.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 sql&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# pwd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/opt/ejabberd-20.04/lib/ejabberd-20.04/priv/sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改为使用&lt;a class="link" href="https://docs.ejabberd.im/tutorials/mysql/" target="_blank" rel="noopener"&#10; &gt;MySQL&lt;/a&gt;存储和认证&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /opt/ejabberd/conf/ejabberd.yml&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&amp;#39; ejabberd configuration file&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### The parameters used in this configuration file are explained at&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### https://docs.ejabberd.im/admin/configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### The configuration file is written in YAML.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### *******************************************************&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### ******* !!! WARNING !!! *******&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### ******* YAML IS INDENTATION SENSITIVE *******&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY *******&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### *******************************************************&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;###&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;vagrant-centos64&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loglevel: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rotate_size: &lt;span style="color:#ae81ff"&gt;10485760&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rotate_date: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rotate_count: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;log_rate_limit: &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certfiles:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;/opt/ejabberd/conf/server.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## - &amp;#34;/etc/letsencrypt/live/localhost/fullchain.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## - &amp;#34;/etc/letsencrypt/live/localhost/privkey.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ca_file: &lt;span style="color:#e6db74"&gt;&amp;#34;/opt/ejabberd/conf/cacert.pem&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5222&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_c2s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_stanza_size: &lt;span style="color:#ae81ff"&gt;262144&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shaper: c2s_shaper&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access: c2s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; starttls_required: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5269&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_s2s_in&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_stanza_size: &lt;span style="color:#ae81ff"&gt;524288&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5443&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_http&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tls: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request_handlers:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/admin&amp;#34;&lt;/span&gt;: ejabberd_web_admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/api&amp;#34;&lt;/span&gt;: mod_http_api&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/bosh&amp;#34;&lt;/span&gt;: mod_bosh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/captcha&amp;#34;&lt;/span&gt;: ejabberd_captcha&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/upload&amp;#34;&lt;/span&gt;: mod_http_upload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/ws&amp;#34;&lt;/span&gt;: ejabberd_http_ws&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/oauth&amp;#34;&lt;/span&gt;: ejabberd_oauth&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;5280&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: ejabberd_http&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; request_handlers:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/admin&amp;#34;&lt;/span&gt;: ejabberd_web_admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port: &lt;span style="color:#ae81ff"&gt;1883&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: &lt;span style="color:#e6db74"&gt;&amp;#34;::&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: mod_mqtt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; backlog: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s2s_use_starttls: optional&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acl:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_regexp: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; loopback:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 127.0.0.0/8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ::1/128&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ::FFFF:127.0.0.1/128&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; admin:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;admin@vagrant-centos64&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;access_rules:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c2s:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deny: blocked&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; announce:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; configure:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; muc_create:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pubsub_createnode:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; trusted_network:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow: loopback&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;api_permissions:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;console commands&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; from:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ejabberd_ctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - mod_http_api&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; who: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; what: &lt;span style="color:#e6db74"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;admin access&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; who:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: loopback&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; oauth:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; scope: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd:admin&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: loopback&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; acl: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; what:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;!stop&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;!start&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;public commands&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; who:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip: 127.0.0.1/8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; what:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - connected_users_number&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shaper:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; normal: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fast: &lt;span style="color:#ae81ff"&gt;50000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;shaper_rules:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_user_sessions: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_user_offline_messages:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 5000: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 100: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c2s_shaper:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; none: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; normal: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; s2s_shaper: fast&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_fsm_queue: &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;acme:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; contact: &lt;span style="color:#e6db74"&gt;&amp;#34;mailto:admin@vagrant-centos64&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ca_url: &lt;span style="color:#e6db74"&gt;&amp;#34;https://acme-v01.api.letsencrypt.org&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;modules:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_adhoc: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_admin_extra: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_announce:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access: announce&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_avatar: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_blocking: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_bosh: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_caps: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_carboncopy: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_client_state: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_configure: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_disco: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_fail2ban: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_http_api: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_http_upload:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; put_url: https://@HOST@:5443/upload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_last: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_mam:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Mnesia is limited to 2GB, better to use an SQL backend&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## For small servers SQLite is a good fit and is very easy&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## to configure. Uncomment this when you have SQL configured:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## db_type: sql&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; assume_mam_usage: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: never&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_mqtt: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_muc:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_admin:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - allow: admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_create: muc_create&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_persistent: muc_create&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_mam:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default_room_options:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; allow_subscription: true &lt;span style="color:#75715e"&gt;# enable MucSub&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mam: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_muc_admin: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_offline:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_max_user_messages: max_user_offline_messages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_ping: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_privacy: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_private: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_proxy65:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access: local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_connections: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_pubsub:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_createnode: pubsub_createnode&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plugins:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - flat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - pep&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; force_node_config:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Avoid buggy clients to make their bookmarks public&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; storage:bookmarks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_model: whitelist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_push: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_push_keepalive: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_register:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Only accept registration requests from the &amp;#34;trusted&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## network (see access_rules section above).&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## Think twice before enabling registration from any&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## address. See the Jabber SPAM Manifesto for details:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;## https://github.com/ge0rg/jabber-spam-fighting-manifesto&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ip_access: trusted_network&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_roster:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; versioning: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_s2s_dialback: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_shared_roster: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_stream_mgmt:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resend_on_timeout: if_offline&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_vcard: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_vcard_xupdate: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mod_version:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; show_os: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_method: sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_type: mysql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_server: &lt;span style="color:#e6db74"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_database: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_username: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sql_password: &lt;span style="color:#e6db74"&gt;&amp;#34;ejabberd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_db: sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## If you want to specify the port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#sql_port: 3306&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### Local Variables:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### mode: yaml&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### End:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;### vim: set filetype=yaml tabstop=8&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;试着注册一下管理员&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./ejabberdctl register admin1 localhost admin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Error: cannot_register&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;失败了，这是因为hostname的关系，在ejabberd.yml配置的host并不是localhost，改一下注册的domain就好了，具体可以参考&lt;a class="link" href="https://www.ejabberd.im/node/14744/index.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;和&lt;a class="link" href="https://github.com/processone/ejabberd/issues/2837" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./ejabberdctl status&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The node ejabberd@localhost is started with status: started&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 logs&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# hostname -s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant-centos64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./ejabberdctl register admin vagrant-centos64 admin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User admin@vagrant-centos64 successfully registered&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问http://127.0.0.1:5280/admin就可以进入到管理界面了。管理界面比较简单，只能管理用户/消息/聊天室，完整的xmpp协议服务器是支持的，客户端对应实现就好了。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/ejabberd_user.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="486px" data-flex-grow="202" height="148" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/ejabberd_user-300x148.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/ejabberd_message.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="679px" data-flex-grow="283" height="106" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/ejabberd_message-300x106.png" width="300"&gt;&lt;/a&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/ejabberd_muc.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="923px" data-flex-grow="384" height="78" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/ejabberd_muc-300x78.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;使用&lt;a class="link" href="https://conversejs.org/" target="_blank" rel="noopener"&#10; &gt;conversejs&lt;/a&gt;快速搭建一个web客户端来验证一下，创建chat.html&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;chat&lt;span style="color:#f92672"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;media=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;screen&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdn.conversejs.org/dist/converse.min.css&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdn.conversejs.org/dist/converse.min.js&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;charset=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; converse.initialize({&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //bosh_service_url: &amp;#39;http://chat.vagrant-centos64.com/bosh&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; websocket_url: &amp;#39;wss:chat.vagrant-centos64.com/ws&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; //show_controlbox_by_default: true,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; view_mode: &amp;#39;fullscreen&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开浏览器，访问对应的url登录就可以看到了聊天界面了。这里使用的域名是经过nginx代理转发过的了，配置可以参考&lt;a class="link" href="https://courages.us/api-%e7%bd%91%e5%85%b3-kong/" target="_blank" rel="noopener"&#10; &gt;API 网关 Kong&lt;/a&gt;，如果使用nginx-proxy-servier需要打开Websockets Support，以便进行协议升级101 Switching Protocols。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/convesejs_login.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="365px" data-flex-grow="152" height="197" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/convesejs_login-300x197.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_one.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="791px" data-flex-grow="329" height="91" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_one-300x91.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_chatroom.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="800px" data-flex-grow="333" height="90" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_chatroom-300x90.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;conversejs配置里面有两个url，一个是&lt;a class="link" href="https://conversejs.org/docs/html/setup.html#bosh-xmpp-over-http" target="_blank" rel="noopener"&#10; &gt;BOSH&lt;/a&gt;（Bidirectional-streams Over Synchronous HTTP）的，即HTTP长连接，以便通服务器即时交互，获取消息；另一个是WebSocket，基于TCP的，客户端/服务器双向通信。BOHS需要浏览器定时发起一个请求直致服务器返回消息，而WebSocket可以像其他TCP那样双向通信，灵活的多。如果服务端不支持Websocket协议升级或者连接失败conversejs会自动切换使用BOSH通信。如果使用https://www.websocket.org/echo.html来测试连接，需要遵循XMPP协议要求，先认证，否则连接会被关闭。conversejs的认证是在Websocket里面的做的，并不基于cookie之类的，所以一个浏览器打开多个聊天窗口登录不同的账户也是可以的&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_con_fail.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="346px" data-flex-grow="144" height="208" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_con_fail-300x208.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/conversejs_con_success.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="642px" data-flex-grow="267" height="112" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/conversejs_con_success-300x112.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/converjs_websocket.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="923px" data-flex-grow="384" height="78" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/converjs_websocket-300x78.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Ejabberd支持&lt;a class="link" href="https://docs.ejabberd.im/developer/ejabberd-api/admin-api/" target="_blank" rel="noopener"&#10; &gt;REST API&lt;/a&gt;来做交互比如查看在线用户、发送消息&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ chat-example git:&lt;span style="color:#f92672"&gt;(&lt;/span&gt;master&lt;span style="color:#f92672"&gt;)&lt;/span&gt; ✗ curl -k https://192.168.33.14:5443/api/connected_users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;admin@vagrant-centos64/converse.js-16142875&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ➜ chat-example git:&lt;span style="color:#f92672"&gt;(&lt;/span&gt;master&lt;span style="color:#f92672"&gt;)&lt;/span&gt; ✗ curl -k https://192.168.33.14:5443/api/send_message -X POST -d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;type&amp;#34;:&amp;#34;headline&amp;#34;,&amp;#34;from&amp;#34;:&amp;#34;test@vagrant-centos64&amp;#34;,&amp;#34;to&amp;#34;:&amp;#34;admin@vagrant-centos64&amp;#34;,&amp;#34;subject&amp;#34;:&amp;#34;Restart&amp;#34;,&amp;#34;body&amp;#34;:&amp;#34;In 5 minutes&amp;#34;}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些API将大大增加ejabberd与第三方软件的交互。虽然ejabberd支持&lt;a class="link" href="https://docs.ejabberd.im/developer/ejabberd-api/admin-api/" target="_blank" rel="noopener"&#10; &gt;OAuth认证&lt;/a&gt;，但那是以ejabberd为账户中心的认证，方便其他系统调用ejabberd功能。通常即时通信只是内部系统的一部分，账户中心部署在其他地方，所以需要ejabberd支持外部的认证。前边已经配置ejabberd为数据库认证，还可以配置为使用LDAP认证。如果不满足，还可以配置为&lt;a class="link" href="https://docs.ejabberd.im/admin/configuration/authentication/" target="_blank" rel="noopener"&#10; &gt;外部脚本认证&lt;/a&gt;或者使用第三方开发的&lt;a class="link" href="https://github.com/processone/ejabberd-contrib/tree/master/ejabberd_auth_http" target="_blank" rel="noopener"&#10; &gt;HTTP认证&lt;/a&gt;。对于简单的内部交互，可以将认证服务的token刷新到ejabberd的数据库即可。&lt;br&gt;&#10;&lt;a class="link" href="https://www.igniterealtime.org/projects/openfire/" target="_blank" rel="noopener"&#10; &gt;Openfire&lt;/a&gt;则是ignite realtime出品的Java实现的XMPP服务器，同时提供Java客户端Spark、Java开发库Smack，还提供Chrome扩展&lt;a class="link" href="https://github.com/igniterealtime/Pade" target="_blank" rel="noopener"&#10; &gt;Pade&lt;/a&gt;。Openfire提供基于web的管理界面，支持LDAP登录及数据库存储。有一些功能Openfire并不直接支持，比如API，而是以&lt;a class="link" href="https://igniterealtime.org/projects/openfire/plugins.jsp" target="_blank" rel="noopener"&#10; &gt;扩展&lt;/a&gt;的形式支持，包括用户管理/分组管理/聊天室管理/消息广播/邮件监听/WebSocket/Meeting/Sip等等。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_user.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="774px" data-flex-grow="322" height="93" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_user-300x93.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;用户管理&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_user_group.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="450px" data-flex-grow="187" height="160" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_user_group-300x160.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;配置用户分组，可以配置部门之类的，会出现在用户的个人分组里面（Spark）&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_chat_session_1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="808px" data-flex-grow="337" height="89" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_chat_session_1-300x89.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;在线会话管理，可以踢人&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_chat_service.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="447px" data-flex-grow="186" height="161" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_chat_service-300x161.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/11/openfire_chat_conference.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="541px" data-flex-grow="225" height="133" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/11/openfire_chat_conference-300x133.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;创建聊天室之前需要创建对应的service，默认的service叫conference。&lt;br&gt;&#10;Openfire的API并不支持OAuth/SSO，简单的1V1消息发送，聊天室消息订阅等等，需要自己基于Java扩展。&lt;br&gt;&#10;Ejabberd是采用Erlang开发的，一如消息队列服务器RabbitMQ，具有极高吞吐能力，提供REST API/XMl RPC，方便交互；Openfire则易于管理和扩展，采用哪个软件进行开发需要结合企业实际进行考量。&lt;br&gt;&#10;XMPP服务器主要提供消息聊天，对于语音服务可以使用SIP服务器实现，结合客户端&lt;a class="link" href="https://sipjs.com/" target="_blank" rel="noopener"&#10; &gt;sip.js&lt;/a&gt;，比如&lt;a class="link" href="https://collecttix.github.io/ctxSip/" target="_blank" rel="noopener"&#10; &gt;ctxSip&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/tcp-udp%e6%8e%a2%e7%b4%a2/" target="_blank" rel="noopener"&#10; &gt;TCP UDP探索&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%B0%8D%E8%A9%B1%E5%95%9F%E5%8B%95%E5%8D%94%E5%AE%9A" target="_blank" rel="noopener"&#10; &gt;SIP（会话发起协议）&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>API 网关 Kong</title><link>https://courages.us/api-%E7%BD%91%E5%85%B3-kong/</link><pubDate>Wed, 28 Oct 2020 10:35:51 +0800</pubDate><guid>https://courages.us/api-%E7%BD%91%E5%85%B3-kong/</guid><description>&lt;p&gt;从前开发一个互联网服务程序，大概可以在一台机器上完成：数据库、应用都在一起。随着业务发展壮大，会把数据库独立出来，以便扩展拆分。然后再把一部分公用业务独立出来扩展，譬如文件存储、缓存等。接着业务也才拆分，比如会员、商品。微服务大行其道，各个团队维护着许多服务、API。这么多服务，前端业务逻辑该怎么接入呢？&lt;br&gt;&#10;如今单一的前端UI也可能是多个团队共同开发的结果。当你在本地开发一个小功能时，甚至会牵扯到多个前端UI/后端API。一个前端页面除了加载自己的资源外，还加载V2/V3的API（为什么会同时存在V1/V2/V3的API），甚至嵌入了另外一个页面（React看起来也不错），该怎么调试这种混合开发呢？cookie都传递不过去，好吧，使用&lt;a class="link" href="http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html" target="_blank" rel="noopener"&#10; &gt;JWT&lt;/a&gt;代替，再设置一下&lt;a class="link" href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS" target="_blank" rel="noopener"&#10; &gt;跨源资源共享（CORS）&lt;/a&gt;。。。但是那些旧的应用怎么办？&lt;br&gt;&#10;当我们启动一个Node.js应用时npm run start，默认监听3000端口。当然我们也可以让它监听80端口。但是当我们多开几个应用时，只好让它们都监听不同端口了，怎么样才能统一端口监听呢？当然Node.js可以通过诸如&lt;a class="link" href="https://github.com/http-party/node-http-proxy" target="_blank" rel="noopener"&#10; &gt;node-http-proxy&lt;/a&gt;来转发这些请求，但是代理转发跟应用业务无关吧？如果是其他编程语言呢？都重复这些代理配置/开发吗？Don’t Repeat Yourself。&lt;br&gt;&#10;&lt;a class="link" href="https://www.redhat.com/zh/topics/cloud-native-apps/what-is-faas" target="_blank" rel="noopener"&#10; &gt;Faas&lt;/a&gt;也日渐流行，比如&lt;a class="link" href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener"&#10; &gt;AWS Lambda&lt;/a&gt;， 强调仅仅专注某个功能，根据事件驱动进行计算，那么每个服务也要开发一整套路由分发/认证/日志吗？&lt;br&gt;&#10;这些问题可以使用反向代理来解决，提供统一的服务入口，对前端/客户端隐藏背后的细节，最简单的当然是Nginx。Nginx监听来自某个端口（比如80）的请求，然后根据不同的来源/端口/域名/url分发给不同的后端服务器。这看起来跟云服务厂商各自开发的负载均衡器差不多，比如&lt;a class="link" href="https://aws.amazon.com/cn/elasticloadbalancing/" target="_blank" rel="noopener"&#10; &gt;AWS ELB&lt;/a&gt;。&lt;br&gt;&#10;在本地开发的时候，我们当然不会使用ELB来解决。直接使用Nginx当然也没啥问题，编辑一下配置文件，重启应用。但是如果有个UI就更好了，如果还有API就非常好了-这样就能方便的在线注册/更改路由而不需要重启服务器，在这个快速发展、弹性开发的年代更需要这个能力。&lt;br&gt;&#10;&lt;a class="link" href="https://konghq.com/kong/" target="_blank" rel="noopener"&#10; &gt;Kong&lt;/a&gt;是一个基于OpenResty的网关服务器，可以进行路由（转发/负载），插件（日志/认证/监控）管理，并提供RESTful API。而&lt;a class="link" href="https://openresty.org/" target="_blank" rel="noopener"&#10; &gt;OpenResty&lt;/a&gt; 是一个基于Nginx与Lua的高性能Web平台，使用Lua来构建动态网关。听起来像是在Nginx上面编程，这跟在Apache上面使用PHP模块进行编程有什么区别？最大的区别在于，这里的编程对象是Nginx（或者公共模块），扩展Nginx能力，比如负载均衡/日志/认证/监控，而不是输出web页面/业务逻辑。这些东西抽出来以后，就不需要每个模块再重复开发了，比如认证/安全。&lt;br&gt;&#10;在本地可以使用docker来运行Kong服务，麻烦在于数据库迁移工作。通常部署Kong需要几个步骤，比如初始化数据库，迁移升级等等。网上的配置大都过时了，这里可以使用官方提供&lt;a class="link" href="https://github.com/Kong/docker-kong/blob/master/compose/docker-compose.yml" target="_blank" rel="noopener"&#10; &gt;docker-compose.yml&lt;/a&gt;来做数据库工作，并且使用&lt;a class="link" href="https://github.com/pantsel/konga" target="_blank" rel="noopener"&#10; &gt;Konga&lt;/a&gt;作为管理UI&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;POSTGRES_PASSWORD data docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong ls data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;postgresql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong cat POSTGRES_PASSWORD&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kong&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong cat docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;version: &lt;span style="color:#e6db74"&gt;&amp;#39;3.7&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong_data: &lt;span style="color:#f92672"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong-net:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; external: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong-migrations:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_DOCKER_TAG&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong:latest&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command: kong migrations bootstrap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_DATABASE: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong-migrations-up:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_DOCKER_TAG&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong:latest&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command: kong migrations up &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; kong migrations finish&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_DATABASE: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_DOCKER_TAG&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong:latest&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user: &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_ADMIN_ACCESS_LOG: /dev/stdout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_ADMIN_ERROR_LOG: /dev/stderr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_ADMIN_LISTEN: &lt;span style="color:#e6db74"&gt;&amp;#39;0.0.0.0:8001&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_CASSANDRA_CONTACT_POINTS: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_DATABASE: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PROXY_ACCESS_LOG: /dev/stdout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PROXY_ERROR_LOG: /dev/stderr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;8000:8000/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8001:8001/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;8443:8443/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8444:8444/tcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; healthcheck:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; test: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;kong&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;health&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval: 10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout: 10s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; retries: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: postgres:9.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; POSTGRES_DB: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; POSTGRES_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong_postgres_password&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; healthcheck:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; test: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;pg_isready&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-U&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval: 30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout: 30s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; retries: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart_policy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; condition: on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stdin_open: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tty: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - /Users/xxxx/docker/kong/data/postgresql:/var/lib/postgresql/data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; konga:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: pantsel/konga&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TOKEN_SECRET: channing.token&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_ADAPTER: postgres&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_HOST: db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_USER: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_USER&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_PASSWORD: kong&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DB_DATABASE: &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;KONG_PG_DATABASE&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;kong&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 1337:1337&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - kong-net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;secrets:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kong_postgres_password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file: ./POSTGRES_PASSWORD&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行docker-composer up就可以看到&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;20ebe7885c0d kong:latest &lt;span style="color:#e6db74"&gt;&amp;#34;/docker-entrypoint.…&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds &lt;span style="color:#f92672"&gt;(&lt;/span&gt;healthy&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 0.0.0.0:8000-&amp;gt;8000/tcp, 127.0.0.1:8001-&amp;gt;8001/tcp, 0.0.0.0:8443-&amp;gt;8443/tcp, 127.0.0.1:8444-&amp;gt;8444/tcp kong_kong_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4a7a39c863ae pantsel/konga &lt;span style="color:#e6db74"&gt;&amp;#34;/app/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds 0.0.0.0:1337-&amp;gt;1337/tcp kong_konga_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aa732758fc51 postgres:9.5 &lt;span style="color:#e6db74"&gt;&amp;#34;docker-entrypoint.s…&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds &lt;span style="color:#f92672"&gt;(&lt;/span&gt;health: starting&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 5432/tcp kong_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问http://127.0.0.1:1337/即可以进入Konga 管理界面了。8000/8443端口是需要监听转发的端口，8001/8444则是Kong RESTFUl管理API的端口。这里也可以把8000/8443改为80/443，这样访问的时候就可以直接使用域名/localhost而不必加端口了。&lt;br&gt;&#10;注册登录进去后首先要添加Kong RESTFUl管理API的地址，这里使用的是docker环境，IP是动态分配的，所以使用链接名就可以了&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.20.50-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="562px" data-flex-grow="234" height="128" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.20.50-PM-300x128.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;连接上Kong API后可以看到dashboard列出了支持的插件&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-09-29-at-3.57.34-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="545px" data-flex-grow="227" height="132" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-09-29-at-3.57.34-PM-300x132.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Kong里面的管理对象是service，路由转发/插件都是围绕service展开的，添加一个service&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.19-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="433px" data-flex-grow="180" height="166" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.19-PM-300x166.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.28-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="354px" data-flex-grow="147" height="203" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.27.28-PM-300x203.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;在它上面添加一个路由，这里我们在服务只监听以/api开头的url，并转发到后端服务器去&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.37-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="431px" data-flex-grow="179" height="167" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.37-PM-300x167.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.48-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="260px" data-flex-grow="108" height="276" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.30.48-PM-300x276.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;注意这里在route里面的path里面也需要添加/api，否则转发的时候会出错（多拼api）。最简单就是service监听不指定path，在route里指定。一个service下面可以有多个转发路由，每个可以独立管理、设置超时等。&lt;br&gt;&#10;还可以为每个service绑定不同的插件进行处理，比如认证/安全/日志等等，这样就不用在不同的系统里面重复开发这些功能，使得各个团队更加专注也本业务开发&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.44.18-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="404px" data-flex-grow="168" height="178" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.44.18-PM-300x178.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.03-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="365px" data-flex-grow="152" height="197" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.03-PM-300x197.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.13-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="336px" data-flex-grow="140" height="214" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-4.45.13-PM-300x214.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;有效插件还可以进行流量限制、请求头/响应头修改等等。这些插件的功能需要基于consumer来开发管理，功能可以非常强大，详细可以参考&lt;a class="link" href="https://github.com/qianyugang/kong-docs-cn/blob/master/HUB/basic-auth.md" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;。&lt;br&gt;&#10;Kong还有一项功能Upstream配置，与Nginx的&lt;a class="link" href="http://nginx.org/en/docs/http/ngx_http_upstream_module.html" target="_blank" rel="noopener"&#10; &gt;ngx_http_upstream_module&lt;/a&gt;差不多，可以作为负载均衡、流量分发控制使用。可以用命令行测试基于hostname的路由，&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ kong curl -i -X GET &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --url http://localhost:8000/ &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --header &lt;span style="color:#e6db74"&gt;&amp;#39;Host: dev1.example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP/1.1 &lt;span style="color:#ae81ff"&gt;404&lt;/span&gt; Not Found&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Date: Tue, &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 08:41:58 GMT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Content-Type: application/json; charset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;utf-8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection: keep-alive&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Content-Length: &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Kong-Response-Latency: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Server: kong/2.1.4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;no Route matched with those values&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt; ➜ kong curl -i -X GET &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --url http://localhost:8000/ &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --header &lt;span style="color:#e6db74"&gt;&amp;#39;Host: dev.example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP/1.1 &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Content-Type: text/html; charset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;UTF-8&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transfer-Encoding: chunked&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection: keep-alive&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Date: Tue, &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;2020&lt;/span&gt; 08:42:21 GMT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Server: Apache/2.2.15 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;CentOS&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Powered-By: PHP/5.6.40&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Set-Cookie: PHPSESSID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0uc3aoc735j21sk3ni5s72vjc1; path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Expires: Thu, &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; Nov &lt;span style="color:#ae81ff"&gt;1981&lt;/span&gt; 08:52:00 GMT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cache-Control: no-store, no-cache, must-revalidate, post-check&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0, pre-check&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Pragma: no-cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Access-Control-Allow-Credentials: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Access-Control-Allow-Headers: X-CSRF-Token,Authorization,X-Accept-Charset,X-Accept,Content-Type&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Kong-Upstream-Latency: &lt;span style="color:#ae81ff"&gt;8397&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X-Kong-Proxy-Latency: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Via: kong/2.1.4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html PUBLIC &lt;span style="color:#e6db74"&gt;&amp;#34;-//W3C//DTD XHTML 1.0 Strict//EN&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;作为一个API网关，Kong能做的很多。如果只是在本地简单的做反向代理，可以使用&lt;a class="link" href="https://github.com/jc21/nginx-proxy-manager" target="_blank" rel="noopener"&#10; &gt;nginx-proxy-manager&lt;/a&gt;，这也是一个基于Nginx开发的网关，根据WEB UI动态生成Nginx配置文件，然后执行/usr/sbin/nginx -s reload生效。有些参数不能通过UI配置（比如超时设置），可以直接写Nginx配置，upstream则支持直接转发tcp请求，支持websockets代理转发，甚至集成了&lt;a class="link" href="https://courages.us/lets-encrypt/" target="_blank" rel="noopener"&#10; &gt;Let’s encrypt&lt;/a&gt;自动申请SSL证书（需要验证域名）&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.03.05-PM.jpg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="576px" data-flex-grow="240" height="125" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.03.05-PM-300x125.jpg" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.10.57-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="217px" data-flex-grow="90" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.10.57-PM-272x300.png" width="272"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.47-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="123px" data-flex-grow="51" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.47-PM-154x300.png" width="154"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.54-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="219px" data-flex-grow="91" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.11.54-PM-274x300.png" width="274"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.13.20-PM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="666px" data-flex-grow="277" height="108" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2020/10/Screen-Shot-2020-10-27-at-5.13.20-PM-300x108.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;本地同样可以使用docker跑起来，默认监听80/443端口，81端口即管理界面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager ls -lah&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; xxxx domain users 192B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 10:24 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; xxxx domain users 480B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 09:15 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; xxxx domain users 2.3K Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 09:42 config.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; xxxx domain users 256B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 09:31 data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; xxxx domain users 740B Sep &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; 10:24 docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; xxxx domain users 96B Oct &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt; 16:38 letsencrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager cat docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;version: &lt;span style="color:#e6db74"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: &lt;span style="color:#e6db74"&gt;&amp;#39;jc21/nginx-proxy-manager:latest&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Public HTTP Port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;80:80&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Public HTTPS Port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;443:443&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Admin Web Port:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;81:81&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# TCP Forward Example:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#39;8022:8022&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Make sure this config.json file exists as per instructions above:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./config.json:/app/config/production.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./data:/data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./letsencrypt:/etc/letsencrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: jc21/mariadb-aria&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_ROOT_PASSWORD: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_DATABASE: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_USER: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_PASSWORD: &lt;span style="color:#e6db74"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./data/mysql:/var/lib/mysql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3dd58e9cff1f jc21/nginx-proxy-manager:latest &lt;span style="color:#e6db74"&gt;&amp;#34;/init&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; weeks ago Up &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; days &lt;span style="color:#f92672"&gt;(&lt;/span&gt;healthy&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 0.0.0.0:80-81-&amp;gt;80-81/tcp, 0.0.0.0:443-&amp;gt;443/tcp, 0.0.0.0:8022-&amp;gt;8022/tcp nginx-proxy-manager_app_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;a033151b28ed jc21/mariadb-aria &lt;span style="color:#e6db74"&gt;&amp;#34;/scripts/run.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; weeks ago Up &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; days 3306/tcp nginx-proxy-manager_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;nginx-proxy-manager会将配置写在data目录下面，可以直接编辑这些文件，Nginx reload之后便会生效，可以看到这些文件，具体的加载规则参考&lt;a class="link" href="https://nginxproxymanager.com/advanced-config/#custom-nginx-configurations" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager ls data/nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dead_host default_host default_www dummycert.pem dummykey.pem proxy_host redirection_host stream temp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager cat data/nginx/proxy_host/1.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# dev.example.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $forward_scheme http;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $server &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.14&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $port 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name dev.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_log /data/logs/proxy_host-1.log proxy;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_connect_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_send_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_read_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;send_timeout 600;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /Login &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass https://login.example.com:443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /api/v2 &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.14:9070;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /api/v3 &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass https://dev.ops.example.com:443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /Chat &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass https://dev.ops.example.com:443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /Catalog &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.1:3000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /static &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.1:3000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /css &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Scheme $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://192.168.33.1:3000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Proxy!&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include conf.d/include/proxy.conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Custom&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /data/nginx/custom/server_proxy&lt;span style="color:#f92672"&gt;[&lt;/span&gt;.&lt;span style="color:#f92672"&gt;]&lt;/span&gt;conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ nginx-proxy-manager cat data/nginx/stream/1.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 8022 TCP: 1 UDP: 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ------------------------------------------------------------&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8022;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:8022;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass 192.168.33.14:22;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Custom&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /data/nginx/custom/server_stream&lt;span style="color:#f92672"&gt;[&lt;/span&gt;.&lt;span style="color:#f92672"&gt;]&lt;/span&gt;conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /data/nginx/custom/server_stream_tcp&lt;span style="color:#f92672"&gt;[&lt;/span&gt;.&lt;span style="color:#f92672"&gt;]&lt;/span&gt;conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在docker-compose.yml里面设置一下upstream监听转发的端口，就可以通过8022端口访问192.168.33.14的22端口了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜  nginx-proxy-manager telnet 127.0.0.1 &lt;span style="color:#ae81ff"&gt;8022&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Trying 127.0.0.1...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connected to localhost.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Escape character is &lt;span style="color:#e6db74"&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSH-2.0-OpenSSH_5.3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;^C^C^C^C^C^C^CConnection closed by foreign host.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不论是Kong还是nginx-proxy-manager均有提供API，极大的增强服务网关的可编程性，为动态上线/弹性扩展/自动化运维提供了便利。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://aws.amazon.com/cn/blogs/china/iaas-faas-serverless/" target="_blank" rel="noopener"&#10; &gt;从IaaS到FaaS—— Serverless架构的前世今生&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://developer.51cto.com/art/202004/615649.htm" target="_blank" rel="noopener"&#10; &gt;聊一聊微服务网关 Kong&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://cloud.tencent.com/developer/article/1435756" target="_blank" rel="noopener"&#10; &gt;KONG网关 — KongA管理UI使用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://juejin.im/post/6844903924911063053" target="_blank" rel="noopener"&#10; &gt;云原生架构下的 API 网关实践： Kong （二）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://xie.infoq.cn/article/ba0f7503c73b86126017c0d32" target="_blank" rel="noopener"&#10; &gt;微服务 API 网关 -Kong 详解&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://dev.to/bambattajb/creating-an-api-with-lua-using-openresty-42mc" target="_blank" rel="noopener"&#10; &gt;Creating a web API with Lua using Nginx OpenResty&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://cloud.tencent.com/developer/article/1027563" target="_blank" rel="noopener"&#10; &gt;Nginx基于TCP/UDP端口的四层负载均衡（stream模块）配置梳理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.jianshu.com/p/45cb044ba99d" target="_blank" rel="noopener"&#10; &gt;Nginx支持TCP代理和负载均衡-stream模块&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.scienjus.com/api-gateway-and-netflix-zuul/" target="_blank" rel="noopener"&#10; &gt;聊聊 API Gateway 和 Netflix Zuul&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.servicemesher.com/envoy/intro/what_is_envoy.html" target="_blank" rel="noopener"&#10; &gt;Envoy 是什么？&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>MySQL事务隔离级别</title><link>https://courages.us/mysql%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB/</link><pubDate>Mon, 23 Sep 2019 14:52:34 +0800</pubDate><guid>https://courages.us/mysql%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB/</guid><description>&lt;p&gt;MySQL的&lt;a class="link" href="https://dev.mysql.com/doc/refman/5.6/en/innodb-introduction.html" target="_blank" rel="noopener"&#10; &gt;InnoDB存储引擎&lt;/a&gt;实现了事务，行级锁，优化主键查询，支持外键等等。事务遵循ACID特征：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;A：原子性（atomicity），一个事务要么完全成功，要么完全失败&lt;/li&gt;&#10;&lt;li&gt;C：一致性（consistency），一个事务对数据的修改必须符合数据库预定义的约束，比如字段类型、外键约束等等&lt;/li&gt;&#10;&lt;li&gt;I：隔离性（isolation），多个事务同时进行时，事务之间数据的读写的隔离&lt;/li&gt;&#10;&lt;li&gt;D：持久性（Durability），事务提交成功后，对数据的修改即永久保存的，不会因为系统故障丢失&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;MySQL默认开启autocommit，除非碰到start transaction/commit/rollback等主动事务管理。事务保证了对于写的先后顺序问题，即A事务先开始变更，B事务的变更必须等A事务完成。此外事务也对读提供不容程度的隔离，与&lt;a class="link" href="https://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-isolation-levels.html" target="_blank" rel="noopener"&#10; &gt;隔离级别&lt;/a&gt;有关，包括不同的等级：读未提交（Read uncommitted）、读已提交（read committed）、可重复读（repeatable read）和串行化（Serializable）。串行化为最高隔离级别，在这个隔离级别下面，读写都是顺序的，不会出现这些问题，但效率低下，MySQL默认隔离级别为可重复读。在其他隔离级别下面可能会出现不同的问题&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;隔离级别&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;脏读&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;不可重复读&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;幻读&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;读未提交(Read Uncommitted)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;读已提交(Read Committed)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;可重复读(Repeatable Read)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;串行化(Searializable)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;假设有一个表test结构为&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;test&lt;span style="color:#f92672"&gt;`&lt;/span&gt; (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;id&lt;span style="color:#f92672"&gt;`&lt;/span&gt; int(&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;) unsigned &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; AUTO_INCREMENT,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;total&lt;span style="color:#f92672"&gt;`&lt;/span&gt; int(&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;status&lt;span style="color:#f92672"&gt;`&lt;/span&gt; int(&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt; (&lt;span style="color:#f92672"&gt;`&lt;/span&gt;id&lt;span style="color:#f92672"&gt;`&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) ENGINE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;InnoDB &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; CHARSET&lt;span style="color:#f92672"&gt;=&lt;/span&gt;utf8;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;test&lt;span style="color:#f92672"&gt;`&lt;/span&gt; (&lt;span style="color:#f92672"&gt;`&lt;/span&gt;id&lt;span style="color:#f92672"&gt;`&lt;/span&gt;, &lt;span style="color:#f92672"&gt;`&lt;/span&gt;total&lt;span style="color:#f92672"&gt;`&lt;/span&gt;, &lt;span style="color:#f92672"&gt;`&lt;/span&gt;status&lt;span style="color:#f92672"&gt;`&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;脏读是指A事务读到B事务未提交的事务，B事务可能取消更改，那么A事务读取的数据不可靠&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;update total set total=100 where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;select total from test where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;rollback;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;结果&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;隔离级别&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读未提交(Read Uncommitted)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于可以读取到未提交的数据，total值为100&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据未更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读已提交(Read Committed)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务读取数据时，事务B尚未提交，total值为原始数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据未更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;可重复读（repeatable read）&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务开始前total值未发生改变，total值为原始数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据未更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;不可重复读是指A事务内，读取的记录数据不恒定，两次读取同一记录的值不一样，&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select total from test where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;update test set total=100 where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select total from test where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;结果&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;隔离级别&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读未提交(Read Uncommitted)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于读取数据时不管是否提交，两次读取的total值不一样&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据已更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读已提交(Read Committed)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务读取数据时，事务B已提交，两次读取的total值不一样&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据已更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;可重复读（repeatable read）&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务开始前total值未发生改变，total值为原始数据，两次读取的total值一样&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据已更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;幻读是指A事务内读取的记录跟实际更改的记录不一致，比如查询表内所有符合条件的记录，并使结果加100&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;insert into `test` (`id`, `total`, `status`) values (2，0, 1);&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;update test set total=total+100;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;7&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;结果&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;隔离级别&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读未提交(Read Uncommitted)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于事务A开始时id为2的记录尚未存在，于是更新所有数据；但由于事务B插入数据，于是事务A也更新事务B插入的数据；A事务第二次读取数据时，读出了事务B的数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;  数据插入成功，但随后被事务A更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读已提交(Read Committed)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务第一次读取数据时，id为2的记录尚未存在，于是更新所有数据；但由于事务B插入数据，于是事务A也更新事务B插入的数据；A事务第二次读取数据时，读出了事务B的数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据插入成功，但随后被事务A更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;可重复读（repeatable read）&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务开始前total值未发生改变，id为2的记录尚未存在，于是更新所有数据；但由于事务B插入数据，于是事务A也更新事务B插入的数据；A事务第二次读取数据时，并没有读到事务B的数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据插入成功，但随后被事务A更新&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;或者当数据库里面没有记录时则增加&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;insert into `test` (`id`, `total`, `status`) values (3, 0, 1);&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;insert into `test` (`id`, `total`, `status`) values (3, 0, 1);&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;select * from test;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;7&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;结果&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;隔离级别&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读未提交(Read Uncommitted)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于事务A读取记录时，id为3的记录不存在，于是插入数据；但由于事务B插入数据，于是事务A插入失败；A事务第二次读取时，读取到id为3的数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据插入成功&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读已提交(Read Committed)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务读取数据时，id为3的记录不存在，于是插入数据；但由于事务B插入数据，于是事务A插入失败；A事务第二次读取时，读取到id为3的数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据插入成功&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;可重复读（repeatable read）&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务开始前id为3的记录尚未存在，于是插入数据；但由于事务B插入数据，于是事务A插入失败；A事务第二次读取时，未读取到id为3的数据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;数据插入成功&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;可重复读与读已提交是互斥的，区别在于是否可以读取到已提交的变更，譬如Oracle的隔离级别为读已提交，可以通过 &lt;a class="link" href="https://dev.mysql.com/doc/refman/5.6/en/set-transaction.html" target="_blank" rel="noopener"&#10; &gt;SET TRANSACTION ISOLATION LEVEL&lt;/a&gt; READ COMMITTED更改。&lt;/p&gt;&#10;&lt;p&gt;除了串行化，其他隔离级别对读是不加锁的，这可能会造成一种情况：事务A读取了数据然后做其他事情了（进入循环或耗时计算），事务B也读取了同一行数据并先提交变更，此后事务A也提交变更但没有重新获取最新值，此时事务B的变更丢失（被覆盖），即更新丢失&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select id,total,status from test where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;select status from test where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;update test set status=2 where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;update test set total=200, status=1 where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;select * from test where id=1;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;7&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;commit;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;结果&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;隔离级别&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读未提交(Read Uncommitted)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于事务A第一次读取记录时status为1，A事务更新时，事务B已提交，A事务提交变更重新改写status为1。重新读取记录最新数据可以解决&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;更新丢失&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;读已提交(Read Committed)&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务第一次读取记录时status为1，A事务更新时，事务B已提交，A事务提交变更重新改写status为1。重新读取记录最新数据可以解决&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;更新丢失&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;可重复读（repeatable read）&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;由于A事务开始前id为1的status为1，A事务提交变更覆盖B事务的变更，重新改写status为1。重新读取记录最新数据不能解决。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;更新丢失&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;在隔离级别为串行化的情况下可解决更新丢失，因为它对读也加锁，另一事务的读操作必须等待当前事务完成。可以在查询里面使用&lt;a class="link" href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html" target="_blank" rel="noopener"&#10; &gt;SELECT…FOR UPDATE&lt;/a&gt;为当前事务记录加锁，这样其他事务读取该记录也必须等待，即拿到最新值。其他事务也可以使用NOWAIT快速失败或者SKIP LOCKED跳过对该记录的查询。&lt;/p&gt;&#10;&lt;p&gt;SELECT…FOR UPDATE申请的锁为排他锁，&lt;a class="link" href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html" target="_blank" rel="noopener"&#10; &gt;锁有不同类型&lt;/a&gt;，比如行锁，区间锁，next-key锁等。此外SELECT…FOR SHARE可以加读锁（共享锁），即本次事务获得锁了，其他事务可以读，但是不能更新；如果其他事务先获得锁并开始更新，则本次事务等待。&lt;/p&gt;&#10;&lt;p&gt;对于更新丢失问题，可以将表拆小，这样更新的操作更加细致，比如status和total分开，减少不同进程更新数据的冲突；更新时带上更多条件，比如status=1条件，失败则返回或重试；更前再次刷新数据，比较cache中的版本；其他手段加锁等等。&lt;/p&gt;&#10;&lt;p&gt;SELECT…FOR UPDATE对记录加锁，要注意不同事务之间避免互相等待，造成死锁，比如不同先后为不同记录申请锁&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test where id=1 for update;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test where id=2 for update;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test where id=2 for update;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test where id=1 for update;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;deadlock;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;deadlock;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这样会造成事务A、B互相等待对方事务完成（释放）超时。或者A事务对记录加读锁后等待写锁，而B事务获得写锁了，等待读锁，也会造成死锁&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;操作顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务A&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;事务B&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;start transaction;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test where id=1 for update;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;insert into `test` (`id`, `total`, `status`) values (4, 0, 1);&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;insert into `test` (`id`, `total`, `status`) values (5, 0, 1);&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;select * from test where id=1 for update;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt; &lt;code&gt;deadlock;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;deadlock;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这个问题应该通过合理的程序设计，先避免不同程序对同一记录竞争加锁；分解大事务为小事务，加速事务提交；减少不必要的锁的申请；当需要排他锁时不应先申请共享锁；降级事务隔离等级为读已提交等等。&lt;/p&gt;&#10;&lt;p&gt;参考资料：&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/kismetv/p/10331633.html" target="_blank" rel="noopener"&#10; &gt;深入学习MySQL事务：ACID特性的实现原理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://fivezh.github.io/2019/02/01/MySQL-Transaction-Isolation-Level/" target="_blank" rel="noopener"&#10; &gt;解析MySQL事务隔离级别&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/zhoujinyi/p/3437475.html" target="_blank" rel="noopener"&#10; &gt;MySQL 四种事务隔离级的说明&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000011164489" target="_blank" rel="noopener"&#10; &gt;MySQL 锁机制&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/kismetv/p/10787228.html" target="_blank" rel="noopener"&#10; &gt;【BAT面试题系列】面试官：你了解乐观锁和悲观锁吗？&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用pack/unpack打包/解包二进制数据</title><link>https://courages.us/%E4%BD%BF%E7%94%A8pack-unpack%E6%89%93%E5%8C%85-%E8%A7%A3%E5%8C%85%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%95%B0%E6%8D%AE/</link><pubDate>Wed, 14 Aug 2019 14:24:47 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8pack-unpack%E6%89%93%E5%8C%85-%E8%A7%A3%E5%8C%85%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%95%B0%E6%8D%AE/</guid><description>&lt;p&gt;web开发中，通常使用的API接口协议都是基于HTTP(S)的文本协议，比如JSON或XML。这对于跨编程语言的通信已经没有问题了，但有时候会采用二进制的数据来通信，以便获得更高的性能，比如&lt;a class="link" href="https://zh.wikipedia.org/wiki/Thrift" target="_blank" rel="noopener"&#10; &gt;Apache Thrift&lt;/a&gt;、gRPC/&lt;a class="link" href="https://developers.google.com/protocol-buffers/docs/proto" target="_blank" rel="noopener"&#10; &gt;Protocol Buffer&lt;/a&gt;。各个编程语言都有对应的pack/unpack函数，PHP可以使用&lt;a class="link" href="https://www.php.net/manual/en/function.pack.php" target="_blank" rel="noopener"&#10; &gt;pack&lt;/a&gt;/&lt;a class="link" href="https://www.php.net/manual/en/function.unpack.php" target="_blank" rel="noopener"&#10; &gt;unpack&lt;/a&gt;函数对数据进行二进制编码/解码，它与Perl的&lt;a class="link" href="https://perldoc.perl.org/functions/pack.html" target="_blank" rel="noopener"&#10; &gt;pack&lt;/a&gt;函数比较类似。&lt;br&gt;&#10;PHP的pack函数至少需要两个参数，第一个参数为打包格式，第二个参数开始为打包的数据。每个格式化字符后面可以跟字节长度，对应打包一个数据；也可以用*自动匹配所有后面的数据，具体的格式化字符可以参考&lt;a class="link" href="https://www.php.net/manual/en/function.pack.php" target="_blank" rel="noopener"&#10; &gt;pack函数&lt;/a&gt;页面。来看下面的例子pack.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;C Programming&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;author&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Nuha Ali&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;C Programming Tutorial&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;book_id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6495407&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Telecom Billing&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;author&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Zara Ali&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Telecom Billing Tutorial&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;book_id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6495700&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;title&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;PHP Programinng&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;author&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Channing Huang&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;PHP Programing Tutorial&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;book_id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6495701&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\fopen&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;example&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;wb&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($data &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $row) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\pack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Z50Z50Z100i&amp;#39;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;...&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;\array_values&lt;/span&gt;($row));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;\fwrite&lt;/span&gt;($fp, $bin);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\fclose&lt;/span&gt;($fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有个books数组，每个book包含4个数据：title、author、subject、bookid，对应的格式化是Z50、Z50、Z100、i。Z50意思是打包成50的字节的二进制数据，剩余部分使用NULL填充，这个跟使用a50是类似的，如果要用空格填充则格式化字符应该是A50。Z100类似Z50，不过字节长度为100。i的意思是打包成有符号的整型对应C里面的signed integer，占4个字节。所以每个book应该占50+50+100+4=204字节，3个book总占用612字节。查看一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ls -la | grep example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;612&lt;/span&gt; Aug &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 02:22 example&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用xxd查看它的二进制内容，确定是使用NULL填充不足部分&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ xxd -b example &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000000: &lt;span style="color:#ae81ff"&gt;01000011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; C Prog&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000006: &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; rammin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000000c: &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; g.....&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000012: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000018: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000001e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000024: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000002a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000030: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01001110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; ..Nuha&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000036: &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01000001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; Ali..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000003c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000042: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000048: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000004e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000054: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000005a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000060: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01000011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; ....C &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000066: &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; Progra&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000006c: &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; mming &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000072: &lt;span style="color:#ae81ff"&gt;01010100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; Tutori&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000078: &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; al....&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000007e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000084: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000008a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000090: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000096: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000009c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000a2: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000a8: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000ae: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000b4: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000ba: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000c0: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000c6: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00011100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ....c.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000cc: &lt;span style="color:#ae81ff"&gt;01010100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; Teleco&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000d2: &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01000010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; m Bill&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000d8: &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ing...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000de: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000e4: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000ea: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000f0: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000f6: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00000fc: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01011010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; ..Zara&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000102: &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01000001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; Ali..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000108: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000010e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000114: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000011a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000120: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000126: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000012c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100101&lt;/span&gt; ....Te&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000132: &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; lecom &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000138: &lt;span style="color:#ae81ff"&gt;01000010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; Billin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000013e: &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; g Tuto&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000144: &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; rial..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000014a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000150: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000156: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000015c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000162: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000168: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000016e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000174: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000017a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000180: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000186: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000018c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000192: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11010100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00011101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ....c.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000198: &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01001000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; PHP Pr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000019e: &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; ogrami&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001a4: &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; nng...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001aa: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001b0: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001b6: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001bc: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001c2: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001c8: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01000011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; ..Chan&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001ce: &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01001000&lt;/span&gt; ning H&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001d4: &lt;span style="color:#ae81ff"&gt;01110101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; uang..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001da: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001e0: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001e6: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001ec: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001f2: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001f8: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01001000&lt;/span&gt; ....PH&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;00001fe: &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; P Prog&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000204: &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101110&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100111&lt;/span&gt; raming&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000020a: &lt;span style="color:#ae81ff"&gt;00100000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01010100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101111&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01110010&lt;/span&gt; Tutor&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000210: &lt;span style="color:#ae81ff"&gt;01101001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100001&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01101100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ial...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000216: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000021c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000222: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000228: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000022e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000234: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000023a: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000240: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000246: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000024c: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000252: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0000258: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ......&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000025e: &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11010101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00011101&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;01100011&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;00000000&lt;/span&gt; ....c.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP的unpack函数有三个参数，第一个为解包的格式化字符，第二个为打包过的数据，第三个为起始偏移量。解包后返回一个关联数组，可以在解包的格式化字符串后面跟对应的key。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\fopen&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;example&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;\feof&lt;/span&gt;($fp)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\fread&lt;/span&gt;($fp,&lt;span style="color:#ae81ff"&gt;204&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($data) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\unpack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Z50title/Z50author/Z100subject/ibook_id&amp;#34;&lt;/span&gt;,$data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($arr &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $key &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $value) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $key&lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $value&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\fclose&lt;/span&gt;($fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就可以读取对应的二进制文件，并正确解析出来。&lt;br&gt;&#10;不同的编程语言都可以对二进制文件进行读写。比如C语言里面打包上面的数据&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&amp;lt;stdio.h&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&amp;lt;stdlib.h&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;book&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; title[&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; author[&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; subject[&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FILE &lt;span style="color:#f92672"&gt;*&lt;/span&gt;fp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;book&lt;/span&gt; books[&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;C Programming&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Nuha Ali&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;C Programming Tutorial&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6495407&lt;/span&gt;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;Telecom Billing&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Zara Ali&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Telecom Billing Tutorial&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6495700&lt;/span&gt;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;PHP Programinng&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Channing Huang&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;PHP Programing Tutorial&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6495701&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fopen(&lt;span style="color:#e6db74"&gt;&amp;#34;newbook&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;wb&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(fp &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;Error opening file&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;sizeof books %10lu&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(books));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;sizeof book struct %10lu&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;book&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;sizeof book1 title %10lu&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(books[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].title));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;sizeof book1 author %10lu&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(books[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].author));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;sizeof book1 subject %10lu&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(books[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].subject));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;sizeof book1 id %10lu&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(books[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].id));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fwrite(books, &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(books), &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fclose(fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译运行一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ gcc -o pack pack.c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./pack&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sizeof books &lt;span style="color:#ae81ff"&gt;612&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sizeof book struct &lt;span style="color:#ae81ff"&gt;204&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sizeof book1 title &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sizeof book1 author &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sizeof book1 subject &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sizeof book1 id &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ls -lah | grep newbook&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;612&lt;/span&gt; Aug &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 02:50 newbook&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到生成的文件大小与上面的一样，使用xxd查看的内容也跟上面的一样，并且可以使用unpak.php解析。类似的也可以用C来解析PHP打包的二进制数据&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&amp;lt;stdio.h&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&amp;lt;stdlib.h&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;book&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; title[&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; author[&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; subject[&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FILE &lt;span style="color:#f92672"&gt;*&lt;/span&gt;fp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;book&lt;/span&gt; Book;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fopen(&lt;span style="color:#e6db74"&gt;&amp;#34;example&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(fp &lt;span style="color:#f92672"&gt;==&lt;/span&gt; NULL)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;Error opening file&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fread(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;Book,&lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;book&lt;/span&gt;),&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf( &lt;span style="color:#e6db74"&gt;&amp;#34;Book title : %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, Book.title);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf( &lt;span style="color:#e6db74"&gt;&amp;#34;Book author : %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, Book.author);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf( &lt;span style="color:#e6db74"&gt;&amp;#34;Book subject : %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, Book.subject);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf( &lt;span style="color:#e6db74"&gt;&amp;#34;Book book_id : %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, Book.id);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fclose(fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译运行一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ gcc -o unpack unpack.c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./unpack&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book title : C Programming&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book author : Nuha Ali&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book subject : C Programming Tutorial&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book book_id : &lt;span style="color:#ae81ff"&gt;6495407&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book title : Telecom Billing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book author : Zara Ali&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book subject : Telecom Billing Tutorial&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book book_id : &lt;span style="color:#ae81ff"&gt;6495700&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book title : PHP Programinng&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book author : Channing Huang&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book subject : PHP Programing Tutorial&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Book book_id : &lt;span style="color:#ae81ff"&gt;6495701&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用C的&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E7%BB%93%E6%9E%84%E4%BD%93_%5c%28C%E8%AF%AD%E8%A8%80%5c%29" target="_blank" rel="noopener"&#10; &gt;struct&lt;/a&gt;定义打包解包数据，这里面有两个问题：&lt;a class="link" href="https://www.geeksforgeeks.org/is-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member/" target="_blank" rel="noopener"&#10; &gt;字节对齐&lt;/a&gt;和&lt;a class="link" href="https://en.wikipedia.org/wiki/Null-terminated_string" target="_blank" rel="noopener"&#10; &gt;NULL填充&lt;/a&gt;。字节对齐会导致生成的二进制文件大小与结构体里面定义的不一样，比如将title改为40个字节，整个book预计占用194字节，实际占用196字节（4的倍数），编译器自动填充了2个字节到title后面。所以要注意数据结构体的设计，避免过多对齐浪费。C语言的字符串其实是字符数组加上NUL结束符（\0）,像上面那样初始化字符串是编译器默认填充的是NUL，但如果声明时没有初始化而是在后面赋值，比如strcpy，则可能在NUL后面填充非NUL值，导致在PHP解析出这些不必要的字符，显示不准确，这也是为什么在PHP里面解析时我们使用Z而不是A解析符的原因，它在碰到NUL便返回，不管后面填充的内容了。可以使用memset手动填充不足部分为’\0’，这样子就可以保证剩余部分全为NULL了。&lt;br&gt;&#10;对于unsigned short，unsigned long，float，double还有大端序、小端序，字节顺序可以参考&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。通常网络设备传输的字节序为大端序，而大部分CPU（x86）处理的字节序为小端序。这里只要通信双方沟通统一使用大端序或小端序即可，不需要关心传输过程中的自动转换。比如在PHP里面发送一个数字（4字节）和8个字符（8字节）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;9872&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$socket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\socket_create&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;AF_INET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOCK_STREAM&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOL_TCP&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Unable to create socket&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;\socket_connect&lt;/span&gt;($socket, $host, $port) &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Connect error.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\socket_last_error&lt;/span&gt;($socket))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;\socket_close&lt;/span&gt;($socket);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\socket_strerror&lt;/span&gt;($err) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$binarydata &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\pack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Na8&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;256&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Channing&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bin2hex&lt;/span&gt;($binarydata)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\socket_write&lt;/span&gt; ($socket , $binarydata, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($binarydata));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\socket_close&lt;/span&gt;($socket);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP里面数字的格式化字符是N，即采用大端序32位编码。在GO里面接收，使用大端序解析位数字&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;package main&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;import&lt;/span&gt; (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#34;net&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#34;encoding/binary&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; BUF_SIZE &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;func handleConnection(conn net.Conn) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;defer conn.Close()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;buf :&lt;span style="color:#f92672"&gt;=&lt;/span&gt; make([]byte, BUF_SIZE)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;n, err :&lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn.Read(buf)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; err &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; nil {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;fmt.Printf(&lt;span style="color:#e6db74"&gt;&amp;#34;err: %v&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, err)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//fmt.Printf(&amp;#34;\nreceive：%d bytes，data：%x, %s\n&amp;#34;, n, buf[:4], buf[4:])&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;fmt.Printf(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;receive：%d bytes，data：%d, %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, n, binary.BigEndian.Uint32(buf[&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;]), buf[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;])&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;func &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;ln, err :&lt;span style="color:#f92672"&gt;=&lt;/span&gt; net.Listen(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;:9872&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; err &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; nil {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;fmt.Printf(&lt;span style="color:#e6db74"&gt;&amp;#34;error: %v&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, err)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;conn, err :&lt;span style="color:#f92672"&gt;=&lt;/span&gt; ln.Accept()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; err &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; nil {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;go handleConnection(conn)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行recieve.go 和 send.php，可以正常收发&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ php send.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;000001004368616e6e696e67&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ go run receive.go &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;receive：12 bytes，data：256, Channing&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果在PHP里面使用了不匹配的格式化符号，比如i或者n，GO里面将解析错误。这里也可以采用小端序编码和解析。&lt;br&gt;&#10;pack后的二进制数据可以使用&lt;a class="link" href="https://www.php.net/manual/en/function.bin2hex.php" target="_blank" rel="noopener"&#10; &gt;bin2hex&lt;/a&gt;转换为16进制查看，使用chr转换单个字节为可读性字符。&lt;br&gt;&#10;通常我们读写的是文本文件，这里读写的是二进制文件，文本文件到二进制文件有个&lt;a class="link" href="http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html" target="_blank" rel="noopener"&#10; &gt;编码过程&lt;/a&gt;，比如ASCII、UTF-8。其实文本文件，图片文件，都是二进制文件，都可以使用xxd查看，只不过特定软件能够解析（解码）对应的二进制字节数据。使用xxd查看时，它只能现显示ASCII可打印字符，不能显示的用点号表示。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/index.html" target="_blank" rel="noopener"&#10; &gt;Apache Thrift – 可伸缩的跨语言服务开发框架&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.ibm.com/developerworks/cn/linux/l-cn-gpb/index.html" target="_blank" rel="noopener"&#10; &gt;Google Protocol Buffer 的使用和原理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/halfrost/Halfrost-Field/blob/master/contents/Protocol/Protocol-buffers-encode.md#%E5%85%AD-protocol-buffer-%E7%BC%96%E7%A0%81%E5%8E%9F%E7%90%86" target="_blank" rel="noopener"&#10; &gt;高效的数据压缩编码方式 Protobuf&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://my.oschina.net/goal/blog/195749" target="_blank" rel="noopener"&#10; &gt;PHP: 深入pack/unpack&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.programiz.com/c-programming/c-file-input-output" target="_blank" rel="noopener"&#10; &gt;C Programming Files I/O&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.codediesel.com/php/unpacking-binary-data/" target="_blank" rel="noopener"&#10; &gt;Unpacking binary data in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/luxiaoxun/archive/2012/09/05/2671697.html" target="_blank" rel="noopener"&#10; &gt;大端和小端（Big endian and Little endian）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php-rpc%e5%bc%80%e5%8f%91%e4%b9%8bthrift/" target="_blank" rel="noopener"&#10; &gt;PHP RPC开发之Thrift&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>短网址生成</title><link>https://courages.us/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%94%9F%E6%88%90/</link><pubDate>Wed, 07 Aug 2019 15:25:04 +0800</pubDate><guid>https://courages.us/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%94%9F%E6%88%90/</guid><description>&lt;p&gt;有时候我们想把一个URL分享给别人，如果URL参数太多，或者太长了，生成的二维码就不好扫描，不方便分享。于是便有了缩短网址的需求，比如微博的t.cn，微信的url.cn，Twitter的t.co。甚至有Bitly.com这样的第三方短网址服务商，提供url访问统计/营销。&lt;br&gt;&#10;怎么样将一个长URL映射成短的URL？如果只是单纯的字符串压缩，很难达到，没办法预计URL有多长。将URL MD5后看起来可行，但是有点长，我们不需要那么多位。最简单的就是在数据库里面存储，一个ID对应一个URL。事实上世界上的URL仍然没有超过2的64次方，因此我们采用自增数字ID就可以了，比如数据库自增量或&lt;a class="link" href="https://courages.us/%e5%9f%ba%e4%ba%8eswoole%e5%92%8czookeeper%e7%9a%84id%e7%94%9f%e6%88%90%e5%99%a8/" target="_blank" rel="noopener"&#10; &gt;分布式ID生成器&lt;/a&gt;。使用自增数字ID的好处是它可以作为数据库主键，通过它来查找对应的URL就很快来。但是随着ID的增长，它也会变得很长，我们还可以将它缩短：将一个10进制的数字转换为62进制的字符串，最多只要11个字符就可以了。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/08/64to62.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="2400px" data-flex-grow="1000" height="30" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/08/64to62-300x30.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/08/64to10.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="2000px" data-flex-grow="833" height="36" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/08/64to10-300x36.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;如果能预计需要生成的网址数量，还可以再缩短，譬如世界上的网址数量大概50亿，62的7次方远大于这个数，因此7个字符足够了。&lt;br&gt;&#10;当访问短网址时，需要301/302重定向到原本的长网址。如果是301永久重定向，则搜索引擎会直接显示重定向后的地址。&lt;br&gt;&#10;PHP函数base_convert可以在2和36进制之间转换，对于62进制就不行，这里分享一个Base62 的转换类，可以将10进制数字转换位62进制&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Conversion&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BASE_MIN&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BASE_MAX&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $base, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $aplphabet)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (($base &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MIN&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; ($base &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MAX&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;base convert only require &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MIN&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; &amp;lt;= base &amp;lt;= &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BASE_MAX&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($aplphabet)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;cannot have empty aplphabet&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($base &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\strlen&lt;/span&gt;($aplphabet)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;base convert only require base &amp;lt;= aplphabet length &amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;base&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $base;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $aplphabet;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;encode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $number)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $number &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) $number;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;base&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $reminder &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcmod&lt;/span&gt;($number, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $quotient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcdiv&lt;/span&gt;($number, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;[$reminder];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($quotient) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $reminder &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcmod&lt;/span&gt;($quotient, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $quotient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcdiv&lt;/span&gt;($quotient, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;[$reminder] &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;decode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $number)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;base&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\strlen&lt;/span&gt;($number);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;\strpos&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;, $number[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $length; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\bcadd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\bcmul&lt;/span&gt;($base, $result), (&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;\strpos&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;alphabet&lt;/span&gt;, $number[$i]));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)$result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base62&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;parent&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用a-z表示10-36，A-Z表示37-62。注意这里需要用到&lt;a class="link" href="https://www.php.net/manual/en/book.bc.php" target="_blank" rel="noopener"&#10; &gt;BCMath&lt;/a&gt;扩展，否则对于超过2的32次方的大数字数不准确。也可以使用&lt;a class="link" href="https://www.php.net/manual/en/book.gmp.php" target="_blank" rel="noopener"&#10; &gt;GMP&lt;/a&gt;扩展的gmp_strval函数直接转换。注意gmp使用A-Z表示10-36，a-z表示37-62。&lt;br&gt;&#10;测试一下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/../vendor/autoload.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Conversion\Base62&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$base62 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Base62&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;56800235584&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $encode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $base62&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;encode&lt;/span&gt;($id);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $decode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $base62&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;decode&lt;/span&gt;($encode);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $id&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$encode&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$decode&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; $i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的起始ID可以自定义或者在分布式ID生成器里面更改CUSTOM_EPOCH生成合适的值。&lt;br&gt;&#10;由于这个ID本身就是唯一，映射为固定长度的字符，也可以用来做唯一标识，比如匿名用户的ID，Ngrok三级域名等等。&lt;br&gt;&#10;这个类可以扩展成支持任意2-64进制的转换，更改映射的字符串就行了。&lt;br&gt;&#10;注意这里的Base62转换于PHP函数base64_encode/base64_decode没有任何关系，即使在这个类的基础上增加2个字符支持Base64编码也不一样。&lt;a class="link" href="https://zh.wikipedia.org/wiki/Base64" target="_blank" rel="noopener"&#10; &gt;Base64&lt;/a&gt;是使用64个可打印字符对二进制数据的编码解码，它的编码表与这里定义的不一样。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/soulmachine/system-design/blob/master/cn/tinyurl.md" target="_blank" rel="noopener"&#10; &gt;如何设计一个短网址服务(TinyURL)？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/4964197/converting-a-number-base-10-to-base-62-a-za-z0-9" target="_blank" rel="noopener"&#10; &gt;converting a number base 10 to base 62 (a-zA-Z0-9)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.jgrossi.com/2013/generating-ids-like-youtube-or-bit-ly-using-php/" target="_blank" rel="noopener"&#10; &gt;Generating IDs like Youtube or Bit.ly using PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://marcus.bointon.com/php-base-62-encoding/" target="_blank" rel="noopener"&#10; &gt;PHP Base-62 encoding&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.kerstner.at/2012/07/shortening-strings-using-base-62-encoding/" target="_blank" rel="noopener"&#10; &gt;Shortening Strings (URLs) using Base 62 Encoding&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://kennycason.com/posts/2012-10-24-php-base-n-conversion.html" target="_blank" rel="noopener"&#10; &gt;Base 2, 8, 16, 62, N Conversion – PHP&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>基于Swoole和Zookeeper的分布式ID生成器</title><link>https://courages.us/%E5%9F%BA%E4%BA%8Eswoole%E5%92%8Czookeeper%E7%9A%84id%E7%94%9F%E6%88%90%E5%99%A8/</link><pubDate>Sun, 28 Jul 2019 11:48:22 +0800</pubDate><guid>https://courages.us/%E5%9F%BA%E4%BA%8Eswoole%E5%92%8Czookeeper%E7%9A%84id%E7%94%9F%E6%88%90%E5%99%A8/</guid><description>&lt;p&gt;大部分业务都需要一个唯一标识ID，比如订单ID、消息ID，通常使用的ID就是数据库的自增ID，比如MySQL的AUTO_INCREMENT；有时候这个ID还需要在不同系统里面传递、保存，又要保证唯一性。单机MySQL在高并发请求下面又可能存在锁/性能问题，于是&lt;a class="link" href="http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/" target="_blank" rel="noopener"&#10; &gt;Flicker&lt;/a&gt;使用两台MySQL来生成ID，一台从0开始，一台从1开始，步长为2，这样两台生成的ID不会互相重复，这个方案也可以扩展成N台，自增步长为N即可。&lt;br&gt;&#10;作为一个分布式ID应当避免在不同节点同步ID信息，通常都是基于时间戳和机器信息来生成。比如MongoDB的ObjectId是提前生成的为12字节=4字节UNIX时间戳+3字节机器码+2字节进程ID+2字节计数序列。&lt;br&gt;&#10;如果不需要访问数据库即能生成ID，性能可以更高。比如&lt;a class="link" href="https://en.wikipedia.org/wiki/Universally_unique_identifier" target="_blank" rel="noopener"&#10; &gt;UUID V1&lt;/a&gt;，基于时间戳和网卡，采用128位，可以生成范围非常广的ID，但是生成的16进制值的36位字符串不好排序。在MySQL里面可以通过调整机器码（MAC）和时间戳位置顺序，并&lt;a class="link" href="https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/" target="_blank" rel="noopener"&#10; &gt;采用binary来存储以提高性能&lt;/a&gt;。&lt;br&gt;&#10;Twitter开源的&lt;a class="link" href="https://github.com/twitter-archive/snowflake" target="_blank" rel="noopener"&#10; &gt;Snowflake&lt;/a&gt;则生成64位数字ID，包括41时间戳，10位机器码/节点码，12位计数序列，另外1位保留。采用基于时间戳的数字ID的好处是这个ID可以当作主键，并且已经粗略按时间排好序，可以直接分页读取，省去在时间字段上建立索引。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/07/snowflake.jpeg" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="705px" data-flex-grow="294" height="102" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/07/snowflake-300x102.jpeg" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;分布式ID通常需要用到机器信息（节点ID或MAC），一个机器通常只运行一个服务进程，所以通常不采用Nginx/Apache + PHP。参考&lt;a class="link" href="https://www.callicoder.com/distributed-unique-id-sequence-number-generator/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;实现一个基于Swoole和Zookpeer的64位ID生成器。基于Swoole可以快速开发一个Web/Socket server，不同于Apache/Nginx，它的PHP进程启动后是常驻运行的，资源初始化后可以重复使用，使用Zookpeer来获取当前进程的节点ID，一旦PHP进程退出后便会销毁对应的节点ID。&lt;br&gt;&#10;首先是生成ID&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Exception\IllegalTimeException&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Number&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TOTAL_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EPOCH_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NODE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;SEQUENCE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;MAX_NODE_ID&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;NODE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;MAX_SEQUENCE_NUMBER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SEQUENCE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CUSTOM_EPOCH&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1262332800000&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $lastTimestamp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $sequence &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $nodeId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $nodeId)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $nodeId;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getNodeId&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getTimestamp&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;) (&lt;span style="color:#a6e22e"&gt;\microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CUSTOM_EPOCH&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;generate&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getTimestamp&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($current &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IllegalTimeException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;current timestamp cannot less than before&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($current &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_SEQUENCE_NUMBER&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_waitNextTimestamp&lt;/span&gt;($current);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $current;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $current &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TOTAL_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPOCH_BIT&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getNodeId&lt;/span&gt;() &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TOTAL_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPOCH_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;NODE_BIT&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id &lt;span style="color:#f92672"&gt;|&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sequence&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_waitNextTimestamp&lt;/span&gt;($current)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($current &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lastTimestamp&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getTimestamp&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $current;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里只涉及到ID生成，包括时间戳，序列号获取，而节点ID由其他对象生成并传入。2的42次方减1等于4398046511103，大概就是2109年5月15日，可以使用(2^42-1)/(365*24*60*60*1000)≈139年，距离现在还有90年可以用，仍然是一个非常大的可使用范围。CUSTOM_EPOC是自定义的时间戳偏移量，以便选取合适的ID生成下限和上限。距离现在节点生成的接口定义&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NodeInterface&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;MAX_NODE_ID&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Number&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;NODE_BIT&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里定义了最大节点序号不能超过1023，可以依据自己的需求更改范围。节点ID的实现可以是基于网卡/进程ID/文件配置等等实现，但是不同机器或多进程之间需要不一样的ID或者需要锁保证上面的generate函数。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Zookeeper&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makePath&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $arrPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\explode&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, $path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($arrPath)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $arrPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\array_filter&lt;/span&gt;($arrPath);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $subpath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $flag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($arrPath &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $p) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $subpath &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$p;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;($subpath)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makeNode&lt;/span&gt;($subpath, $value)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $flag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $flag;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;makeNode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $value, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt; $acls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [], &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt; $flag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($acls)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $acls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;perms&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PERM_ALL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;scheme&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;anyone&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;($path, $value, $acls, $flag)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deletePath&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path)&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getChildren&lt;/span&gt;($path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($children)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($children &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $child) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $subpath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$child;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;deletePath&lt;/span&gt;($subpath);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;delete&lt;/span&gt;($path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用Zookeeper实现&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strict_types&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Node&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Exception\UnavailableNodeIdException&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\NodeInterface&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Zookeeper\Client&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NodeInterface&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $zk;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $dsn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $pool;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $basePath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/dig/ticket&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $acls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;perms&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PERM_ALL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;scheme&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;anyone&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $dsn, &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt; $path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/sim/ticket&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dsn&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $dsn;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pool&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\SplQueue&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($path)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $path;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zk&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zk&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dsn&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zk&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;()&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makePath&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\mb_strlen&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $nodeId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;%0&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$length&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;, $i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getChildren&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $children &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($children) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; [] &lt;span style="color:#f92672"&gt;:&lt;/span&gt; $children;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (; $i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt;; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $nodeId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;%0&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$length&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;, $i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;\in_array&lt;/span&gt;($nodeId, $children)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;basePath&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$nodeId;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;($path)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//throw new UnavailableNodeIdException(&amp;#39;node already exist: &amp;#39;.$path);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getZookeeper&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;makeNode&lt;/span&gt;($path, $nodeId, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;acls&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;\Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPHEMERAL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;\ZookeeperException&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//throw new UnavailableNodeIdException(&amp;#39;cannot create node in zookeeper: &amp;#39;.$e-&amp;gt;getMessage());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UnavailableNodeIdException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;cannot create node in zookeeper: reach max node limit &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MAX_NODE_ID&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里遍历查询1-1023之间的节点是否都已在Zookeeper上注册，如果没有则注册，Zookeeper会保证只有一个客户端注册成功。注册的节点类型位Zookeeper::EPHEMERAL，在客户端退出时，该节点会被自动删除，方便其他机器/进程申请。在&lt;a class="link" href="https://courages.us/php-zookeeper%e5%88%86%e5%b8%83%e5%bc%8f%e6%9c%8d%e5%8a%a1%e5%bc%80%e5%8f%91/" target="_blank" rel="noopener"&#10; &gt;这篇&lt;/a&gt;文章里面我们也使用Zookeeper::EPHEMERAL配合Zookeeper::EPHEMERAL，生成序列号，用来确定进程的master/slave。&lt;br&gt;&#10;初始化并运行Swoole Web server，需要传入Zookeeper的连接字符串，可以使用&lt;a class="link" href="https://hub.docker.com/_/zookeeper" target="_blank" rel="noopener"&#10; &gt;docker&lt;/a&gt;快速部署&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/../vendor/autoload.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Number&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Dig\Ticket\Node\Zookeeper&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZookeeperNode&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/** &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * swoole - zookeeper tick dispatch issue: https://github.com/php-zookeeper/php-zookeeper&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getenv&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ZOOKEEPER_CONNECTION&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($host) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.1:2181&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$node &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZookeeperNode&lt;/span&gt;($host);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Swoole\Http\Server&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9501&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;start&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($server) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Swoole http server is started at http://0.0.0.0:9501&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;WorkerStart&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($server, $workerId) &lt;span style="color:#66d9ef"&gt;use&lt;/span&gt;($node) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// https://wiki.swoole.com/wiki/page/325.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// https://wiki.swoole.com/wiki/page/852.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// https://wiki.swoole.com/wiki/page/865.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// use lazy initial zk here, so that each worker can hold its own zk resource&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// if we only run swoole http server in 1 worker process (1 CPU), then no need to consider this&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $node&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Number&lt;/span&gt;($server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nodeId&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;request&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($request, $response) &lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; ($http) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;generate&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $response&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;end&lt;/span&gt;($data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$http&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;start&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问本机的9501端口即可以得到ID了，完整代码在&lt;a class="link" href="https://github.com/llitllie/dig/tree/master/src/Dig" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。Swoole默认运行与CPU核数量相同的worker进程数，注意这里需要WorkerStart里初始化获取Node节点ID，如果只是运行一个Swoole worker进程，也可以在外面获取节点ID。可以将Swool\Htpp\Server替换成React\Http\Server或者Amp\Http\Server，它们在单个进程里面loop，每个进程分别持有自己的节点序号，可以保证生成的ID不冲突，性能方面Swoole &amp;gt; Amp &amp;gt; ReactPHP。&lt;br&gt;&#10;可以采用Swoole\Server + thrift/gRPC改造这些代码，提供RPC服务。&lt;br&gt;&#10;注意ID的生成是随时间递增的，依赖于时间戳，如果出现了时间回拨，将会抛出异常。一般解决方案包括：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;等待重试&lt;/li&gt;&#10;&lt;li&gt;使用Int64原子自增量代替时间戳，跳过时间戳判断&lt;/li&gt;&#10;&lt;li&gt;使用预留的节点ID&lt;/li&gt;&#10;&lt;li&gt;关闭时钟同步&lt;/li&gt;&#10;&lt;li&gt;使用备选自增量方案&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;生成的ID并不是严格递增的，只是千分一秒递增，对于微博、Twiter的Timeline够用；但也有好处，比如别人不能通过ID相减了解美团的订单量。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/soulmachine/system-design/blob/master/cn/distributed-id-generator.md" target="_blank" rel="noopener"&#10; &gt;如何设计一个分布式ID生成器(Distributed ID Generator)，并保证ID按时间粗略有序？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://mp.weixin.qq.com/s?__biz=MzI4MTY5NTk4Ng==&amp;amp;mid=2247489561&amp;amp;idx=1&amp;amp;sn=7396f373af4efa62ba4dbecc6d7f83b3&amp;amp;source=41#wechat_redirect" target="_blank" rel="noopener"&#10; &gt;生成全局唯一ID的3个思路，来自一个资深架构师的总结&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.slideshare.net/nguyentungniit/distributed-unique-id-generation" target="_blank" rel="noopener"&#10; &gt;Distributed unique id generation&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://preparingforcodinginterview.wordpress.com/2017/03/21/unique-id-generation-in-distributed-systems/" target="_blank" rel="noopener"&#10; &gt;Unique ID generation in distributed systems&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stitcher.io/blog/optimised-uuids-in-mysql" target="_blank" rel="noopener"&#10; &gt;Optimised UUIDs in mysql&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://mysqlserverteam.com/storing-uuid-values-in-mysql-tables/" target="_blank" rel="noopener"&#10; &gt;Storing UUID Values in MySQL Tables&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://mysqlserverteam.com/mysql-8-0-uuid-support/" target="_blank" rel="noopener"&#10; &gt;Mysql 8.0: UUID support&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/4444771/how-to-store-a-128-bit-number-in-a-single-column-in-mysql" target="_blank" rel="noopener"&#10; &gt;How to store a 128 bit number in a single column in MySQL?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.callicoder.com/distributed-unique-id-sequence-number-generator/" target="_blank" rel="noopener"&#10; &gt;Generating unique IDs in a distributed environment at high scale&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://tech.meituan.com/2017/04/21/mt-leaf.html" target="_blank" rel="noopener"&#10; &gt;Leaf——美团点评分布式ID生成系统&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.jianshu.com/p/98c202f64652" target="_blank" rel="noopener"&#10; &gt;分布式ID增强篇–优化时钟回拨问题&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/" target="_blank" rel="noopener"&#10; &gt;Ticket Servers: Distributed Unique Primary Keys on the Cheap&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c" target="_blank" rel="noopener"&#10; &gt;Sharding &amp;amp; IDs at Instagram&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用Composer和Docker创建Swoole项目</title><link>https://courages.us/%E4%BD%BF%E7%94%A8composer%E5%92%8Cdocker%E5%88%9B%E5%BB%BAswoole%E9%A1%B9%E7%9B%AE/</link><pubDate>Mon, 01 Jul 2019 16:56:31 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8composer%E5%92%8Cdocker%E5%88%9B%E5%BB%BAswoole%E9%A1%B9%E7%9B%AE/</guid><description>&lt;p&gt;最近有一个小功能使用&lt;a class="link" href="https://www.swoole.com/" target="_blank" rel="noopener"&#10; &gt;swoole&lt;/a&gt;扩展来开发，并没有使用框架，从零开始。这里采用类用似&lt;a class="link" href="https://symfony.com/doc/current/setup.html" target="_blank" rel="noopener"&#10; &gt;Symfony&lt;/a&gt;的目录结构：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── src&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── tests&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── vendor&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── phpunit.xml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── composer.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── .gitignore&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── Dockerfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── LICENSE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── phpunit.xml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── README.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;项目代码放置在src下面，测试代码则在tests里面，config目录存放配置文件，bin文件夹则是一些命令行工具，vendor目录则是&lt;a class="link" href="https://getcomposer.org/doc/01-basic-usage.md" target="_blank" rel="noopener"&#10; &gt;composer&lt;/a&gt;安装第三方依赖库的目录。composer.json是借鉴&lt;a class="link" href="https://github.com/k911/swoole-bundle/blob/develop/composer.json" target="_blank" rel="noopener"&#10; &gt;k911/swoole-bundle&lt;/a&gt;，内容如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;llitllie/swoole-sample&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;library&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Swoole Sample&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;keywords&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Swoole&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;license&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;MIT&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;homepage&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://github.com/llitllie/swoole-sample.git&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;authors&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;llitllie&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;xxx@yyy.zzz&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;homepage&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://github.com/llitllie/swoole-sample.git&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;require&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^7.2&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ext-swoole&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^4.3.4&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;require-dev&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;phpunit/phpunit&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^8&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;phpstan/phpstan&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^0.11.8&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;friendsofphp/php-cs-fixer&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^2.15&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;swoole/ide-helper&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;@dev&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;static-analyse-src&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;phpstan analyze src -l 7 --ansi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cs-analyse&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;php-cs-fixer fix -v --dry-run --diff --stop-on-violation --ansi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;analyse&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;@static-analyse-src&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;@cs-analyse&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;@analyse&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;@unit-tests&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;unit-tests&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;phpunit tests --testdox --colors=always&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;fix&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;php-cs-fixer fix -v --ansi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;suggest&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ext-uv&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^0.2.4&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ext-ev&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;^1.0.6&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里require里面指定了PHP版本&amp;gt;=7.2和Swoole扩展，composer安装时会自动检查。require-dev里面指定了单元测试工具&lt;a class="link" href="https://phpunit.de/" target="_blank" rel="noopener"&#10; &gt;phpunit&lt;/a&gt;、代码分析工具&lt;a class="link" href="https://github.com/phpstan/phpstan" target="_blank" rel="noopener"&#10; &gt;phpstan&lt;/a&gt;和代码风格检查&lt;a class="link" href="https://github.com/FriendsOfPHP/PHP-CS-Fixer" target="_blank" rel="noopener"&#10; &gt;php-cx-fixer&lt;/a&gt;。phpstan可以帮助分析代码，检测语法，在代码运行前发现问题。php-cx-fixer则可以帮忙格式化代码，保持代码统一风格。scripts里面定义了调用它们的命令，可以使用composer运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -la vendor/bin/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxrwxr-x. &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; Jul &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 07:24 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxrwxr-x. &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; Jul &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 07:25 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt; Jul &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 07:24 php-cs-fixer -&amp;gt; ../friendsofphp/php-cs-fixer/php-cs-fixer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;33&lt;/span&gt; Jul &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 07:24 php-parse -&amp;gt; ../nikic/php-parser/bin/php-parse&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; Jul &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 07:24 phpstan -&amp;gt; ../phpstan/phpstan/bin/phpstan&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; vagrant vagrant &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; Jul &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 07:24 phpunit -&amp;gt; ../phpunit/phpunit/phpunit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./vendor/bin/phpunit --testdox tests&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ composer test&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; phpstan analyze src -l &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; --ansi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 7/8 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 87%&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 8/8 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 100% &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;OK&lt;span style="color:#f92672"&gt;]&lt;/span&gt; No errors &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; php-cs-fixer fix -v --dry-run --diff --stop-on-violation --ansi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded config default from &lt;span style="color:#e6db74"&gt;&amp;#34;/home/ticket/.php_cs.dist&amp;#34;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Using cache file &lt;span style="color:#e6db74"&gt;&amp;#34;.php_cs.cache&amp;#34;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSSSSSSSSSS&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Checked all files in 0.070 seconds, 6.000 MB memory used&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; phpunit tests --testdox --colors&lt;span style="color:#f92672"&gt;=&lt;/span&gt;always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHPUnit 8.2.4 by Sebastian Bergmann and contributors.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sim&lt;span style="color:#ae81ff"&gt;\T&lt;/span&gt;icket&lt;span style="color:#ae81ff"&gt;\N&lt;/span&gt;ode&lt;span style="color:#ae81ff"&gt;\Z&lt;/span&gt;ookeeper&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Get id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sim&lt;span style="color:#ae81ff"&gt;\T&lt;/span&gt;icket&lt;span style="color:#ae81ff"&gt;\N&lt;/span&gt;umber&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Load&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Get timestamp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Get node id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Generate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Generate with zookeeper node&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sim&lt;span style="color:#ae81ff"&gt;\Z&lt;/span&gt;ookeeper&lt;span style="color:#ae81ff"&gt;\C&lt;/span&gt;lient&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Zookeeper&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ✓ Zookeeper extension&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;841&lt;/span&gt; ms, Memory: 4.00 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OK &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; tests, &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt; assertions&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="https://phpunit.de/manual/6.5/en/appendixes.configuration.html" target="_blank" rel="noopener"&#10; &gt;phpuit.xml&lt;/a&gt;里面则是一些测试配置，可以在里面定义自动加载和变量&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- https://phpunit.readthedocs.io/en/7.3/configuration.html --&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;xmlns:xsi=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;xsi:noNamespaceSchemaLocation=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://schema.phpunit.de/7.3/phpunit.xsd&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;colors=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;bootstrap=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;vendor/autoload.php&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;filter&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;whitelist&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processUncoveredFilesFromWhitelist=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;directory&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;suffix=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;.php&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;src/&lt;span style="color:#f92672"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/whitelist&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;testsuites&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Unit tests suite&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;tests&lt;span style="color:#f92672"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/testsuites&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;php&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;includePath&amp;gt;&lt;/span&gt;.&lt;span style="color:#f92672"&gt;&amp;lt;/includePath&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SERVICE&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;env&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SERVICE&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/php&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/phpunit&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP Composer支持使用已有的代码作为模板，快速克隆创建一个新项目，方便重复使用。将代码保存到GitHub上面然后在&lt;a class="link" href="https://packagist.org/packages/submit" target="_blank" rel="noopener"&#10; &gt;packagist.org&lt;/a&gt;上面提交就可以了。使用composer create-project：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;composer create-project llitllie/swoole-sample example dev-master&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用&lt;a class="link" href="https://docs.docker.com/engine/reference/builder/" target="_blank" rel="noopener"&#10; &gt;Docker&lt;/a&gt;来构建运行代码，Dockerfile内容如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ARG PHP_TAG&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;7.2-cli-alpine3.9&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FROM php:$PHP_TAG&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ENV COMPOSER_ALLOW_SUPERUSER &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RUN set -ex &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk update &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add --no-cache --virtual .build-deps curl gcc g++ make build-base autoconf &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add libstdc++ openssl-dev libffi-dev &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-php-ext-install sockets &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-php-source extract &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;yes\nyes\nno\nyes\nno\n&amp;#34;&lt;/span&gt; | pecl install swoole &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-php-ext-enable swoole &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-php-source delete &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl -sS https://getcomposer.org/installer | php -- --install-dir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local/bin --filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;composer &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk del .build-deps &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf /tmp/* &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WORKDIR /usr/src/app&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COPY . ./&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ARG COMPOSER_ARGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;install&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RUN composer &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;COMPOSER_ARGS&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; --prefer-dist --ignore-platform-reqs --no-progress --no-suggest --no-scripts --ansi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXPOSE &lt;span style="color:#ae81ff"&gt;9501&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CMD &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;bin/server.php&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里声明了swoole将会监听9501端口，默认运行bin目录下面的serverphp文件。使用pecl安装swoole会要求回答几个问题，比如是否启用socket/http2/mysqlnd等等，这里使用printf输出答案。构建，然后运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker build -t llitllie/swoole-project .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --name swoole -d -p 9501:9501 llitllie/swoole-project&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#docker run --name web -dit -p 9501:9501 --mount type=bind,source=/Users/vagrant/example,target=/opt/app llitllie/swoole-project /bin/sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样一个swoole项目模板算是好了，可以继续往composer文件里面添加需要的库或脚本；也可以继承在已经构建好的docker镜像基础上继续添加所需的软件，更改监听端口等等。&lt;br&gt;&#10;可以在Docker Cloud上面配置对应的git，并配置对应自动化构建规则，这样就可以方便的自动构建了。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/07/docker_git.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="276px" data-flex-grow="115" height="260" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/07/docker_git-300x260.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Jupyter Notebook</title><link>https://courages.us/jupyter-notebook/</link><pubDate>Mon, 03 Jun 2019 15:30:07 +0800</pubDate><guid>https://courages.us/jupyter-notebook/</guid><description>&lt;p&gt;对于编程初学者，如果有一个开箱即用的环境，比如web页面，就可以进行编程交互，那是极友好。有时候我们想在远程服务器上执行一些脚本，输出一些结果，比如科学计算；有时候又想在服务器上执行一些命令但又不能直接登录服务器，如果能够在web界面上操作或作为跳板机，那也是极友好的。&lt;a class="link" href="https://jupyter.org/" target="_blank" rel="noopener"&#10; &gt;Jupyter Notebook&lt;/a&gt;是基于&lt;a class="link" href="https://ipython.org/" target="_blank" rel="noopener"&#10; &gt;IPython&lt;/a&gt;的一个基于web交互执行的在线环境，支持Python，也支持其他编程语言，比如Julia和R。所创建Notebook文档可以自动保存执行过的代码、结果，方便进行回放。&lt;br&gt;&#10;Jupyter Notebok的&lt;a class="link" href="https://jupyter.org/install" target="_blank" rel="noopener"&#10; &gt;安装&lt;/a&gt;很方便，可以使用Anaconda来安装，或者手动安装。Python3下手动安装，&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install jupyter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PATH:/usr/local/python3/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost local&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# pip3 show jupyter&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Name: jupyter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Version: 1.0.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Summary: Jupyter metapackage. Install all the Jupyter components in one go.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Home-page: http://jupyter.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Author: Jupyter Development Team&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Author-email: jupyter@googlegroups.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;License: BSD&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Location: /usr/local/python3/lib/python3.7/site-packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Requires: jupyter-console, notebook, ipywidgets, nbconvert, qtconsole, ipykernel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Required-by: &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果直接运行jupyter notebook，那么会生成一个本地可以访问的带token的url，每次都不一样，不是很方便。设置密码，以便登录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost opt&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# jupyter notebook password&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter password: &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verify password: &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;NotebookPasswordApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Wrote hashed password to /root/.jupyter/jupyter_notebook_config.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /root/.jupyter/jupyter_notebook_config.json &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;NotebookApp&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;sha1:e04153005102:961b12eef91987a06b497f915fc3f18c62d8f714&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于是在虚拟机里面，我们并不需要Jupyter自动打开浏览器，但需要监听来自任意IP的请求，指定端口9030。这里使用root用户运行Jupyter，默认是不允许的：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost opt&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# jupyter notebook --no-browser --allow-root --ip 0.0.0.0 --port 9030&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:13:44.320 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Serving notebooks from local directory: /opt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:13:44.320 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The Jupyter Notebook is running at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:13:44.320 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; http://&lt;span style="color:#f92672"&gt;(&lt;/span&gt;localhost.localdomain or 127.0.0.1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:9030/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:13:44.320 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Use Control-C to stop this server and shut down all kernels &lt;span style="color:#f92672"&gt;(&lt;/span&gt;twice to skip confirmation&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:13:59.664 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;302&lt;/span&gt; GET / &lt;span style="color:#f92672"&gt;(&lt;/span&gt;192.168.33.1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1.22ms&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:14:23.597 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Kernel started: 7ad63717-7a65-4dec-9d5a-9af654c28f75&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:14:25.204 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Adapting to protocol v5.1 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; kernel 7ad63717-7a65-4dec-9d5a-9af654c28f75&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:14:37.350 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Starting buffering &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; 7ad63717-7a65-4dec-9d5a-9af654c28f75:ea68853b742c40f8bcf8745529ea95de&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:14:43.735 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Kernel started: 5b569c8d-6936-4bd2-9674-0317c46948f6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;I 02:14:44.124 NotebookApp&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Adapting to protocol v5.0 &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; kernel 5b569c8d-6936-4bd2-9674-0317c46948f6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2019-06-03 02:14:43&lt;span style="color:#f92672"&gt;]&lt;/span&gt; kernel.DEBUG: Connection settings &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;processId&amp;#34;&lt;/span&gt;:6751,&lt;span style="color:#e6db74"&gt;&amp;#34;connSettings&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;shell_port&amp;#34;&lt;/span&gt;:39990,&lt;span style="color:#e6db74"&gt;&amp;#34;iopub_port&amp;#34;&lt;/span&gt;:48184,&lt;span style="color:#e6db74"&gt;&amp;#34;stdin_port&amp;#34;&lt;/span&gt;:40113,&lt;span style="color:#e6db74"&gt;&amp;#34;control_port&amp;#34;&lt;/span&gt;:43426,&lt;span style="color:#e6db74"&gt;&amp;#34;hb_port&amp;#34;&lt;/span&gt;:49075,&lt;span style="color:#e6db74"&gt;&amp;#34;ip&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;d5f89bba-890ecf15e6b20718411170ad&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;transport&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;signature_scheme&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;hmac-sha256&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;kernel_name&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;jupyter-php&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;connUris&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stdin&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:40113&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;control&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:43426&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;hb&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:49075&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:39990&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;iopub&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:48184&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}}&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2019-06-03 02:14:44&lt;span style="color:#f92672"&gt;]&lt;/span&gt; KernelCore.DEBUG: Initialized sockets &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;processId&amp;#34;&lt;/span&gt;:6751&lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后打开浏览器，访问http://192.168.33.70:9030，输入账号密码，就可以在web里面运行Python了&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/06/jupyter_hello.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="791px" data-flex-grow="329" height="91" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/06/jupyter_hello-300x91.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Jupyter默认带了SQL扩展，使用&lt;a class="link" href="https://pypi.org/project/ipython-sql/" target="_blank" rel="noopener"&#10; &gt;ipython-sql&lt;/a&gt;来执行，只需要安装对应的驱动，这里使用&lt;a class="link" href="https://docs.sqlalchemy.org/en/13/dialects/mysql.html" target="_blank" rel="noopener"&#10; &gt;PyMySQL&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 -m pip install PyMySQL&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在Web里面执行就可以了&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/06/jupyter_sql_dataframe.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="367px" data-flex-grow="153" height="196" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/06/jupyter_sql_dataframe-300x196.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;Jupyter还有其他&lt;a class="link" href="https://github.com/ipython/ipython/wiki/Extensions-Index" target="_blank" rel="noopener"&#10; &gt;扩展&lt;/a&gt;，参考&lt;a class="link" href="https://github.com/ipython-contrib/jupyter_contrib_nbextensions" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;除了可以执行Python和SQL，Jupyter Notebook也可以支持其他语言，在&lt;a class="link" href="https://github.com/jupyter/jupyter/wiki/Jupyter-kernels" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;列出了。通常&lt;a class="link" href="https://jupyter.readthedocs.io/en/latest/architecture/how_jupyter_ipython_work.html" target="_blank" rel="noopener"&#10; &gt;执行方式&lt;/a&gt;是通过Bash执行，或者通过ZeroMQ来通信，参考&lt;a class="link" href="https://jupyter-client.readthedocs.io/en/latest/messaging.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;实现。一个Jupyter的kernal将需要监听以下几个socket：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Shell：执行命令&lt;/li&gt;&#10;&lt;li&gt;IOPub：推送执行结果&lt;/li&gt;&#10;&lt;li&gt;Stdin：接收输入&lt;/li&gt;&#10;&lt;li&gt;Control：接收控制命令，比如关闭、终端&lt;/li&gt;&#10;&lt;li&gt;Heartbeat：心跳检测&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这个思路也可以用来做IOT设备的远程监控，交互执行。&lt;br&gt;&#10;这里安装一下&lt;a class="link" href="https://github.com/Litipk/Jupyter-PHP" target="_blank" rel="noopener"&#10; &gt;PHP 7&lt;/a&gt;这个kernel，作者甚至还提供了&lt;a class="link" href="https://litipk.github.io/Jupyter-PHP-Installer/" target="_blank" rel="noopener"&#10; &gt;installer&lt;/a&gt;，但是首先要安装ZeroMQ以便与Jupyter服务通信&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install php-pecl-zmq&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://litipk.github.io/Jupyter-PHP-Installer/dist/jupyter-php-installer.phar&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./jupyter-php-installer.phar install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看安装文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost opt&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls -la /usr/local/share/jupyter/kernels/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 06:10 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 07:30 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 07:30 jupyter-php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 06:10 lgo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost opt&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /usr/local/share/jupyter/kernels/jupyter-php/kernel.json &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;argv&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;\/opt\/jupyter-php\/pkgs\/vendor\/litipk\/jupyter-php\/src\/kernel.php&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;{connection_file}&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;display_name&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;PHP&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;language&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;env&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个扩展使用了&lt;a class="link" href="https://packagist.org/packages/react/zmq" target="_blank" rel="noopener"&#10; &gt;react/zmq&lt;/a&gt;来监听Jupyter请求，使用&lt;a class="link" href="https://psysh.org/" target="_blank" rel="noopener"&#10; &gt;psysh&lt;/a&gt;来交互执行PHP代码。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/06/jupyter_php.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="734px" data-flex-grow="306" height="98" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/06/jupyter_php-300x98.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;如果想要更改Jupyter的web模板，可以在以下目录找到&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost vagrant&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ls -la /usr/local/python3/lib/python3.7/site-packages/notebook/templates&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;92&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x. &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;147&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 404.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;499&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 browser-open.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4258&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 edit.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;856&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 error.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4256&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 login.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;1179&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 logout.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;23162&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 notebook.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;6559&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 page.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;1089&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 terminal.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;12130&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 tree.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r--. &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;544&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 06:33 view.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Jupyter Notebook Web前端采用WebSocket与服务器交互，服务器接收消息并转发给对应的kernel执行或控制，并将结果推送给前端。Jupyter Notebook也可以直接打开Terminal，在远程服务器上执行命令。注意这里的用户就是刚才运行jupyter的用户&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/06/jupyter_terminal.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="402px" data-flex-grow="167" height="179" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/06/jupyter_terminal-300x179.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;许多web terminal也都是采用WebSocket来做交互，比如&lt;a class="link" href="https://github.com/xtermjs/xterm.js" target="_blank" rel="noopener"&#10; &gt;xterm.js&lt;/a&gt;，&lt;a class="link" href="https://github.com/krishnasrinivas/wetty" target="_blank" rel="noopener"&#10; &gt;webtty&lt;/a&gt;。&lt;br&gt;&#10;Juypter Notebook适合单用户（单机）使用，如果提供多用户使用（比如教学），可以使用&lt;a class="link" href="https://jupyter.org/hub" target="_blank" rel="noopener"&#10; &gt;Jupyter Hub&lt;/a&gt;，可以使用&lt;a class="link" href="https://github.com/jupyter/docker-stacks" target="_blank" rel="noopener"&#10; &gt;docker&lt;/a&gt;快捷部署。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://towardsdatascience.com/jupyter-notebook-extensions-517fa69d2231" target="_blank" rel="noopener"&#10; &gt;Jupyter Notebook Extensions&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://jupyter.readthedocs.io/en/latest/projects/content-projects.html" target="_blank" rel="noopener"&#10; &gt;Jupyter – How do I decide which packages I need?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://vergil.cn/archives/psysh" target="_blank" rel="noopener"&#10; &gt;PsySH——PHP交互式控制台&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/wiki/Jupyter%E9%A1%B9%E7%9B%AE" target="_blank" rel="noopener"&#10; &gt;Jupyter项目&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ruanyifeng.com/blog/2017/05/websocket.html" target="_blank" rel="noopener"&#10; &gt;WebSocket 教程&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Nginx + Frp/Ngrok反向代理Webhook至本地</title><link>https://courages.us/nginx-frp-ngrok%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86webhook%E8%87%B3%E6%9C%AC%E5%9C%B0/</link><pubDate>Wed, 15 May 2019 20:21:20 +0800</pubDate><guid>https://courages.us/nginx-frp-ngrok%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86webhook%E8%87%B3%E6%9C%AC%E5%9C%B0/</guid><description>&lt;p&gt;跟第三方平台打交道，经常需要设置一个接受通知的Webhook，比如微信/Skype的回调。它们要求有一个可以在互联网上访问得了的入口，比如某个域名，如果是在本地开发的话，不好调试。通常使用花生壳来代理本地服务，但是花生壳有一些限制，比如端口。有些域名服务商，比如DNSPOD，Linode，提供相应的API，也可以自己搭建DDNS服务，但是也可能有端口访问限制。&lt;a class="link" href="https://github.com/fatedier/frp" target="_blank" rel="noopener"&#10; &gt;Frp&lt;/a&gt;/&lt;a class="link" href="https://ngrok.com/" target="_blank" rel="noopener"&#10; &gt;Ngrok&lt;/a&gt;都是Go语言开发的内网穿透工具，可以自己部署搭建。Frp是国人开发的一款反向代理软件，可以转发请求给位于NAT后面的机器，支持TCP，UDP，HTTP/HTTPS。Ngrok则是国外的一款内网穿透软件，也支持HTTP/HTTPS转发。这里使用Nginx作为反向代理服务器，接收互联网回调并转发给本地的Frp/Ngrok服务，由它们接收webhook请求并转发至本地开发环境。&lt;br&gt;&#10;前面&lt;a class="link" href="https://courages.us/centos-7%e4%b8%8a%e5%ae%89%e8%a3%85openvpn/" target="_blank" rel="noopener"&#10; &gt;使用OpenVpn搭建了私有网络&lt;/a&gt;，可以在Nginx里面配置转发给目标机器就可以了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/nginx/conf.d/100-dev.example.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内容如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name dev.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;301&lt;/span&gt; https://$host$request_uri;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 443;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name dev.example.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_session_cache builtin:1000 shared:SSL:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ssl_prefer_server_ciphers on;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://10.9.0.2/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用了&lt;a class="link" href="https://courages.us/lets-encrypt/" target="_blank" rel="noopener"&#10; &gt;let’s encryt&lt;/a&gt;的泛域名证书，官方并没有&lt;a class="link" href="https://certbot.eff.org/docs/using.html#dns-plugins" target="_blank" rel="noopener"&#10; &gt;对应的插件&lt;/a&gt;，但是DNSPOD有提供相应的API，第三方开发了一个插件自certbot-dns-dnspod，安装这个插件并且配置Dnspod的API Token：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ yum install certbot python2-certbot-nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ certbot --nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pip install certbot-dns-dnspod&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/letsencrypt/dnspod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot_dns_dnspod:dns_dnspod_email &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;123@163.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot_dns_dnspod:dns_dnspod_api_token &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;123,ca440********&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chmod &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; /etc/letsencrypt/dnspod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;手动请求证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ certbot certonly -a certbot-dns-dnspod:dns-dnspod --certbot-dns-dnspod:dns-dnspod-credentials /etc/letsencrypt/dnspod.conf --server https://acme-v02.api.letsencrypt.org/directory -d example.com -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Saving debug log to /var/log/letsencrypt/letsencrypt.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plugins selected: Authenticator certbot-dns-dnspod:dns-dnspod, Installer None&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: acme-v02.api.letsencrypt.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Obtaining a new certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Performing the following challenges:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns-01 challenge &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns-01 challenge &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: dnsapi.cn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Waiting &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; seconds &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; DNS changes to propagate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; verification...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cleaning up challenges&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Resetting dropped connection: acme-v02.api.letsencrypt.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IMPORTANT NOTES:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - Congratulations! Your certificate and chain have been saved at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /etc/letsencrypt/live/example.com/fullchain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Your key file has been saved at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /etc/letsencrypt/live/example.com/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Your cert will expire on 2019-08-04. To obtain a new or tweaked&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version of this certificate in the future, simply run certbot&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; again. To non-interactively renew *all* of your certificates, run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;certbot renew&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*/1 * * * * /usr/local/qcloud/stargate/admin/start.sh &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &amp;amp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - If you like Certbot, please consider supporting our work by:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Donating to ISRG / Let&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s Encrypt: https://letsencrypt.org/donate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Donating to EFF: https://eff.org/donate-le&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -la /etc/letsencrypt/live/example.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwx------ &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 cert.pem -&amp;gt; ../../archive/example.com/cert1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 chain.pem -&amp;gt; ../../archive/example.com/chain1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;39&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 fullchain.pem -&amp;gt; ../../archive/example.com/fullchain1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lrwxrwxrwx &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;37&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 privkey.pem -&amp;gt; ../../archive/example.com/privkey1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;692&lt;/span&gt; May &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 12:06 README&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置证书自动更新&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0,12 * * * python -c &lt;span style="color:#e6db74"&gt;&amp;#39;import random; import time; time.sleep(random.random() * 3600)&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; certbot renew&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Frp的开发者已经提供了编译好的&lt;a class="link" href="https://github.com/fatedier/frp/releases" target="_blank" rel="noopener"&#10; &gt;frp服务端和客户端&lt;/a&gt;，下载即可使用。这里使用docker来运行Frp服务，使用这个&lt;a class="link" href="https://hub.docker.com/r/yangliu/frps/dockerfile" target="_blank" rel="noopener"&#10; &gt;Dockerfile&lt;/a&gt;，更改版本号为0.26.0，并编译&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker build . -t frps:0.26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;frps 0.26 8a87cb91d4de &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago 21.1MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下SSH代理服务，创建服务端配置文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p frp/conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim frp/conf/frps.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;frps.ini内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bind_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行一下frp服务端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#清除先前运行的容器&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker rm frp-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ docker run --name frp-server -v /root/frp/conf:/conf -p 7000:7000 -p 6000:6000 frps:0.26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:17 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:136&lt;span style="color:#f92672"&gt;]&lt;/span&gt; frps tcp listen on 0.0.0.0:7000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:17 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;root.go:204&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Start frps success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:337&lt;span style="color:#f92672"&gt;]&lt;/span&gt; client login info: ip &lt;span style="color:#f92672"&gt;[&lt;/span&gt;110.87.98.82:61894&lt;span style="color:#f92672"&gt;]&lt;/span&gt; version &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0.26.0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; hostname &lt;span style="color:#f92672"&gt;[]&lt;/span&gt; os &lt;span style="color:#f92672"&gt;[&lt;/span&gt;linux&lt;span style="color:#f92672"&gt;]&lt;/span&gt; arch &lt;span style="color:#f92672"&gt;[&lt;/span&gt;386&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tcp.go:66&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; tcp proxy listen port &lt;span style="color:#f92672"&gt;[&lt;/span&gt;6000&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:398&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; new proxy &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:41 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;110.*.*.*:61894&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里映射了2个端口，端口7000是frp服务端监听的端口，以便客户端能够连接上；端口6000是需要服务端监听这个端口，以便提供反向代理服务，比如SSH。如果使用的是腾讯云，相应的端口需要在安全组放行。&lt;br&gt;&#10;客户端直接下对应的包，里面有配置试例。创建本地配置文件frpc.ini如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 123.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tcp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local_ip &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 127.0.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;remote_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个配置即告诉服务端，将服务端的6000端口转发到本地的22端口。本地运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./frpc -c ./frpc.ini.ssh &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:221&lt;span style="color:#f92672"&gt;]&lt;/span&gt; login to server success, get run id &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt;, server udp port &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy_manager.go:137&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;e8783ecea2085e15&lt;span style="color:#f92672"&gt;]&lt;/span&gt; proxy added: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/04/22 06:41:27 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:144&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ssh&lt;span style="color:#f92672"&gt;]&lt;/span&gt; start proxy success&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在服务端连接客户端。这里连接的是服务端的6000端口，会被转发给远程（局域网内）主机&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;rth@centos72&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ssh -oPort&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6000&lt;/span&gt; vagrant@123.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The authenticity of host &lt;span style="color:#e6db74"&gt;&amp;#39;[123.*.*.*]:6000 ([123.*.*.*]:6000)&amp;#39;&lt;/span&gt; can&lt;span style="color:#e6db74"&gt;&amp;#39;t be established.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;RSA key fingerprint is SHA256:NhBO/PDL***********************.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;RSA key fingerprint is MD5:20:70:e2:*:*:*:*:*:*:*:*:*:*:*:*:*.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Are you sure you want to continue connecting (yes/no)? yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Warning: Permanently added &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:6000&lt;span style="color:#e6db74"&gt;&amp;#39; (RSA) to the list of known hosts.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;vagrant@123.*.*.*&amp;#39;&lt;/span&gt;s password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Last login: Mon Apr &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; 06:39:07 &lt;span style="color:#ae81ff"&gt;2019&lt;/span&gt; from 10.0.2.2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;logout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Connection to 123.*.*.* closed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Frp转发http服务很简单。在conf目录下创建配置frps.ini监听本机来自8080端口的HTTP请求&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bind_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vhost_http_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos frp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker run --name frp-server -v /root/frp/conf:/conf -p 7000:7000 -p 8080:8080 frps:0.26&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:28 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:136&lt;span style="color:#f92672"&gt;]&lt;/span&gt; frps tcp listen on 0.0.0.0:7000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:28 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:178&lt;span style="color:#f92672"&gt;]&lt;/span&gt; http service listen on 0.0.0.0:8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:28 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;root.go:204&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Start frps success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:337&lt;span style="color:#f92672"&gt;]&lt;/span&gt; client login info: ip &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt; version &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0.26.0&lt;span style="color:#f92672"&gt;]&lt;/span&gt; hostname &lt;span style="color:#f92672"&gt;[]&lt;/span&gt; os &lt;span style="color:#f92672"&gt;[&lt;/span&gt;linux&lt;span style="color:#f92672"&gt;]&lt;/span&gt; arch &lt;span style="color:#f92672"&gt;[&lt;/span&gt;386&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;http.go:72&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; http proxy listen &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; host &lt;span style="color:#f92672"&gt;[&lt;/span&gt;test.example.com&lt;span style="color:#f92672"&gt;]&lt;/span&gt; location &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:398&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; new proxy &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:05 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:05 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:06 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy.go:82&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; get a new work connection: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;123.*.*.*:56758&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后配置Nginx转发请求&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/nginx/conf.d/100-dev.example.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-Proto $scheme;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:8080/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建本地web传教客户端配置frpc.ini，将来自服务器dev.example.com:8080端口的HTTP请求转发至本地80端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;common&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 123.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; http&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local_port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;custom_domains &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dev.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行本地客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 frp&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./frpc -c ./frpc.ini&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:221&lt;span style="color:#f92672"&gt;]&lt;/span&gt; login to server success, get run id &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt;, server udp port &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;proxy_manager.go:137&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;19f60a30aa924343&lt;span style="color:#f92672"&gt;]&lt;/span&gt; proxy added: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:26:51 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:144&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;web&lt;span style="color:#f92672"&gt;]&lt;/span&gt; start proxy success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;E&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:127&lt;span style="color:#f92672"&gt;]&lt;/span&gt; work connection closed, EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;control.go:228&lt;span style="color:#f92672"&gt;]&lt;/span&gt; control writer is closing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2019/05/06 07:27:37 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;I&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;service.go:127&lt;span style="color:#f92672"&gt;]&lt;/span&gt; try to reconnect to server...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问dev.example.com既可以看到本地web服务器页面。Frp还可以代理其他请求，也有在它基础上二次加工提供基于token认证的转发服务。&lt;br&gt;&#10;Ngrok 2.0以后不再开源，只能使用1.3版本的搭建。这里使用&lt;a class="link" href="https://github.com/hteen/docker-ngrok" target="_blank" rel="noopener"&#10; &gt;docker-ngrok&lt;/a&gt;来构建。Ngrok构建需要SSL证书，复制刚才生成的letsencypt证书并更改server.sh&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git clone https://github.com/hteen/docker-ngrok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/fullchain.pem myfiles/base.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/fullchain.pem myfiles/fullchain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/privkey.pem myfiles/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim server.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -e&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DOMAIN&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;**None**&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Please set DOMAIN&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; ! -f &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/bin/ngrokd&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;ngrokd is not build,will be build it now...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /bin/sh /build.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/bin/ngrokd -tlsKey&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/privkey.pem -tlsCrt&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;MY_FILES&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/fullchain.pem -domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DOMAIN&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; -httpAddr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;HTTP_ADDR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; -httpsAddr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;HTTPS_ADDR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; -tunnelAddr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;TUNNEL_ADDR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构建Ngrok镜像&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos docker-ngrok&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker build -t ngrok:1.3 .&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos docker-ngrok&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker images&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ngrok 1.3 dc70190d6377 &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; seconds ago 260MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;frps 0.26 8a87cb91d4de &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; hours ago 21.1MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alpine latest cdf98d1859c1 &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; days ago 5.53MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后交叉编译生成Linux/Mac/Windows平台的客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rm -rf assets/client/tls/ngrokroot.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/chain.pem assets/client/tls/ngrokroot.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rm -rf assets/server/tls/snakeoil.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/cert.pem assets/server/tls/snakeoil.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rm -rf assets/server/tls/snakeoil.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cp /etc/letsencrypt/live/example.com/privkey.pem assets/server/tls/snakeoil.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;linux GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;amd64 make release-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;windows GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;amd64 make release-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;darwin GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;amd64 make release-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在服务器上运行Ngrok服务，将8090端口请求转发给容器的80端口，并且映射容器的4443端口到服务器的7000端口，以便客户端连接&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@VM_1_218_centos docker-ngrok&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# docker run --name ngrok -e DOMAIN=&amp;#39;example.com&amp;#39; -p 8090:80 -p 8091:443 -p 7000:4443 -v /root/docker-ngrok/myfiles:/myfiles ngrok:1.3 /bin/sh /server.sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;registry&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun&lt;span style="color:#f92672"&gt;]&lt;/span&gt; No affinity cache specified&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.Info:112&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Listening &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; public http connections on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:80&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.Info:112&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Listening &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; public https connections on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:443&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.Info:112&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Listening &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; control and proxy connections on &lt;span style="color:#f92672"&gt;[&lt;/span&gt;::&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:4443&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:21 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;metrics&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Reporting every &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt; seconds&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; New connection from 123.*.*.*:50529&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Waiting to read message&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Reading message with length: &lt;span style="color:#ae81ff"&gt;125&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;tun:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Read message &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;Auth&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Payload&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;MmVersion&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;1.7&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;User&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Password&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;OS&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Arch&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;ClientId&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Renamed connection tun:18e8cd42&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;INFO&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Info:83&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;registry&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Registered control with id 1957f20b9b3ce3b76c7d8fc8b16276ed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1957f20b9b3ce3b76c7d8fc8b16276ed&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Writing message: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;AuthResp&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Payload&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;MmVersion&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;1.7&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;ClientId&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;1957f20b9b3ce3b76c7d8fc8b16276ed&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Error&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1957f20b9b3ce3b76c7d8fc8b16276ed&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Writing message: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Type&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;ReqProxy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;Payload&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;{}}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;09:18:27 UTC 2019/05/07&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;DEBG&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;ngrok/log.&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*PrefixLogger&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.Debug:79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ctl:18e8cd42&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1957f20b9b3ce3b76c7d8fc8b16276ed&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Waiting to read message&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将刚才编译的客户端下载下来，创建grok.cfg，连接服务器的7000端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server_addr: &lt;span style="color:#e6db74"&gt;&amp;#34;example.com:7000&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;trust_host_root_certs: false&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;指定要监听的域名，及本地web端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./ngrok -config&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ngrok.cfg -subdomain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dev &lt;span style="color:#ae81ff"&gt;9010&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ngrok &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Ctrl+C to quit&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Tunnel Status online &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Version 1.7/1.7 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Forwarding http://dev.flexkit.cn -&amp;gt; 127.0.0.1:9010 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Forwarding https://dev.flexkit.cn -&amp;gt; 127.0.0.1:9010 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Web Interface 127.0.0.1:4040 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Conn 2 &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Avg Conn Time 46.84ms &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTP Requests &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------------- &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GET /teams &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; OK &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请求dev.example.com即可以访问到本机9010端口的web服务。&lt;br&gt;&#10;附：&lt;a class="link" href="https://www.zerotier.com/" target="_blank" rel="noopener"&#10; &gt;ZeroTier&lt;/a&gt;是一个软件定义网络（SDN）软件，可以免费组建私有网络，当然也可以用来转发服务器请求至本地。&lt;/p&gt;&#10;&lt;p&gt;参考链接：：&lt;br&gt;&#10;&lt;a class="link" href="https://www.xncoding.com/2017/12/29/web/ngrok.html" target="_blank" rel="noopener"&#10; &gt;CentOS7搭建ngrok服务器&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/inconshreveable/ngrok" target="_blank" rel="noopener"&#10; &gt;inconshreveable/ngrok&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://hub.docker.com/r/hteen/ngrok/dockerfile" target="_blank" rel="noopener"&#10; &gt;hteen/ngrok&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://fengqi.me/unix/409.html" target="_blank" rel="noopener"&#10; &gt;搭建自己的 Ngrok 服务器, 并与 Nginx 并存&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.lylinux.net/article/2018/9/18/51.html" target="_blank" rel="noopener"&#10; &gt;使用Docker部署Ngrok实现内网穿透&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.v2ex.com/t/394739" target="_blank" rel="noopener"&#10; &gt;Laravel DDNS package，可代替花生壳之类的软件&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.jianshu.com/p/7294cf136b25" target="_blank" rel="noopener"&#10; &gt;通过DNSPod API实现动态域名解析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://medium.com/@vista8/%E5%80%9F%E5%8A%A9dnspod-api%E5%AE%9A%E6%97%B6%E6%9B%B4%E6%96%B0%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90%E8%8E%B7%E5%8F%96%E6%A0%91%E8%8E%93%E6%B4%BE%E5%85%AC%E7%BD%91ip-1e460651596b" target="_blank" rel="noopener"&#10; &gt;借助dnspod-api定时更新域名解析获取树莓派公网ip&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://latlonworld.com/article/free-wildcard-ssl-with-lets-encrypt.html" target="_blank" rel="noopener"&#10; &gt;使用Let’s Encrypt生成通配符SSL证书&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.sharpbai.com/2017/07/letsencrypt%E4%BD%BF%E7%94%A8dnspod%E9%AA%8C%E8%AF%81%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0%E8%AF%81%E4%B9%A6/" target="_blank" rel="noopener"&#10; &gt;Letsencrypt使用DNSPOD验证自动更新证书&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://tommy.net.cn/2015/02/25/use-dnspod-as-ddns-on-openwrt/" target="_blank" rel="noopener"&#10; &gt;在 OpenWrt 环境下使用 DnsPod 来实现动态域名解析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/kwongtai/p/6903420.html" target="_blank" rel="noopener"&#10; &gt;利用ssh反向代理以及autossh实现从外网连接内网服务器&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-with-ssl-as-a-reverse-proxy-for-jenkins" target="_blank" rel="noopener"&#10; &gt;How To Configure Nginx with SSL as a Reverse Proxy for Jenkins&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用SkPy创建Skype群组会话</title><link>https://courages.us/%E4%BD%BF%E7%94%A8skpy%E5%88%9B%E5%BB%BAskype%E7%BE%A4%E7%BB%84%E4%BC%9A%E8%AF%9D/</link><pubDate>Wed, 08 May 2019 09:30:56 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8skpy%E5%88%9B%E5%BB%BAskype%E7%BE%A4%E7%BB%84%E4%BC%9A%E8%AF%9D/</guid><description>&lt;p&gt;每一次产品发布或故障支持，都需要将相关人员拉到同一个Skype群聊会话，以便讨论、测试、支持。如果每次都需要手动做这些动作是比较累；如果复用已有会话，又会影响本次无关人员。于是有了这样一个需求：在Web后台定义相关组员及关联关系，在Web前台点击即可以创建或加入相关会话。这要求提供一个HTTP的接口，接收会话人员及主题，创建聊天室。搜了一圈，发现&lt;a class="link" href="https://github.com/Terrance/SkPy" target="_blank" rel="noopener"&#10; &gt;SkPy&lt;/a&gt;这个库最简单，支持创建会话，发送/接收消息，事件监听等等，其他的库要么功能太简单不满足，要么需要安装Skype客户端，要么不支持最新（live）注册的Skype用户，决定使用这个来开发。由于只是一个简单的HTTP接口，决定使用&lt;a class="link" href="http://webpy.org/" target="_blank" rel="noopener"&#10; &gt;web.py&lt;/a&gt;。&lt;br&gt;&#10;首先安装SkPy和web.py，注意如果是CentOS 6，Python certifi版本只能是2015.04.28，否则会报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pip install SkPy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pip install web.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#you need to do follow steps on Centos 6.x, to make requests works&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pip uninstall -y certifi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pip install certifi&lt;span style="color:#f92672"&gt;==&lt;/span&gt;2015.04.28&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;web.py只要单个文件就可以工作了，创建chat.py如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; skpy &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Skype&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; skpy &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SkypeAuthException&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; logging&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; hashlib&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os.path&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; io&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;urls &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/chat&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;chat&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;try:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; import http.client as http_client&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;except ImportError:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; # Python 2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; import httplib as http_client&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;http_client.HTTPConnection.debuglevel = 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;logging.basicConfig()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;logging.getLogger().setLevel(logging.DEBUG)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;requests_log = logging.getLogger(&amp;#34;requests.packages.urllib3&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;requests_log.setLevel(logging.DEBUG)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;requests_log.propagate = True&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SkypeService&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;username &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;skype account&amp;gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;password &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;skype password&amp;gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;token_file&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/tmp/tokens-app&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Skype(connect&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;setTokenFile(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getTokenFile())&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getTokenFile&lt;/span&gt;(self):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;isfile(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;token_file):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; io&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;token_file, &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; file:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;token_file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(self):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;readToken()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; SkypeAuthException:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;setUserPwd(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;username, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;password)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getSkypeToken()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;creatChatRoom&lt;/span&gt;(self, member, topic):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;chats&lt;span style="color:#f92672"&gt;.&lt;/span&gt;create(members&lt;span style="color:#f92672"&gt;=&lt;/span&gt;member)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;setTopic(topic)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getShardLink&lt;/span&gt;(self, channel):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; channel&lt;span style="color:#f92672"&gt;.&lt;/span&gt;joinUrl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;createAndGetSharedLink&lt;/span&gt;(self, member, topic):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;connect()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;creatChatRoom(member, topic)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# ch.sendMsg(&amp;#34;welcome&amp;#34;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# return {&amp;#34;id&amp;#34;: ch.id, &amp;#34;url&amp;#34;: self.getShardLink(ch)}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getShardLink(ch)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getConversationIdByUrl&lt;/span&gt;(self, url):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;chats&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urlToIds(url)[&lt;span style="color:#e6db74"&gt;&amp;#34;Resource&amp;#34;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getChatroomByUrl&lt;/span&gt;(self, url):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getConversationIdByUrl(url)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getChatroomByConversationId(id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getChatroomByConversationId&lt;/span&gt;(self, id):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;skype&lt;span style="color:#f92672"&gt;.&lt;/span&gt;chats&lt;span style="color:#f92672"&gt;.&lt;/span&gt;chat(id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sendMessageByConversationId&lt;/span&gt;(self, id, message):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getChatroomByConversationId(id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sendMsg(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello world!&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getMessagesByConversationId&lt;/span&gt;(self, id):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getChatroomByConversationId(id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getMsgs()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Storage&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cache_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/tmp/&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(self, key, value):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cache_path &lt;span style="color:#f92672"&gt;+&lt;/span&gt; key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; io&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(cache_file, &lt;span style="color:#e6db74"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; file:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(value)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;file: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{0}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; write failure&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(cache_file))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(self, key):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cache_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cache_path &lt;span style="color:#f92672"&gt;+&lt;/span&gt; key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; io&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open(cache_file) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; file:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;file: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{0}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; not exists&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(cache_file))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; value&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GET&lt;/span&gt;(self):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello, world!&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chat&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GET&lt;/span&gt;(self):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; url &lt;span style="color:#f92672"&gt;=&lt;/span&gt; web&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctx&lt;span style="color:#f92672"&gt;.&lt;/span&gt;home &lt;span style="color:#f92672"&gt;+&lt;/span&gt; web&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctx&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path &lt;span style="color:#f92672"&gt;+&lt;/span&gt; web&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctx&lt;span style="color:#f92672"&gt;.&lt;/span&gt;query&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hashlib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;md5(url)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;hexdigest()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; storage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Storage()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; join_url &lt;span style="color:#f92672"&gt;=&lt;/span&gt; storage&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(key)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; param &lt;span style="color:#f92672"&gt;=&lt;/span&gt; web&lt;span style="color:#f92672"&gt;.&lt;/span&gt;input()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; users &lt;span style="color:#f92672"&gt;=&lt;/span&gt; param&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; member &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tuple(users&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split(&lt;span style="color:#e6db74"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; topic &lt;span style="color:#f92672"&gt;=&lt;/span&gt; param&lt;span style="color:#f92672"&gt;.&lt;/span&gt;topic&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sk &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SkypeService()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; join_url &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sk&lt;span style="color:#f92672"&gt;.&lt;/span&gt;createAndGetSharedLink(member, topic)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; storage&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(key, join_url)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; join_url&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app &lt;span style="color:#f92672"&gt;=&lt;/span&gt; web&lt;span style="color:#f92672"&gt;.&lt;/span&gt;application(urls, globals())&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后运行chat.py，默认监听8080端口&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python chat.py &lt;span style="color:#f92672"&gt;[&lt;/span&gt;port&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在浏览器访问，&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://127.0.0.1:8080/chat?user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;user1,user2&amp;amp;topic&lt;span style="color:#f92672"&gt;=&lt;/span&gt;19.5Release&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即可以创建一个聊天会话，并且返回join url，点击这个URL会尝试打开Skype应用。注意这个会话默认是开放的，允许任何人加入&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://join.skype.com/LRRUuan7kNH3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;去掉logging注释，可以看到API调用的过程，作者也作了详细的&lt;a class="link" href="https://skpy.t.allofti.me/protocol/start.html" target="_blank" rel="noopener"&#10; &gt;协议文档&lt;/a&gt;，可以看出&lt;a class="link" href="https://skpy.t.allofti.me/protocol/login.html" target="_blank" rel="noopener"&#10; &gt;登录流程&lt;/a&gt;相当复杂，也可以根据这个开放出其他语言的SDK。&lt;br&gt;&#10;注意这个bot运行的是个人账号，使用的是与web.skype.com相同的HTTP API，最好是在&lt;a class="link" href="https://dev.skype.com/bots" target="_blank" rel="noopener"&#10; &gt;Skype 开发者平台&lt;/a&gt;上注册，官方也提供了&lt;a class="link" href="https://docs.microsoft.com/en-us/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0" target="_blank" rel="noopener"&#10; &gt;NodeJS的SDK&lt;/a&gt;。&lt;br&gt;&#10;之前许多QQ机器人使用都是&lt;a class="link" href="https://web2.qq.com/" target="_blank" rel="noopener"&#10; &gt;Web QQ&lt;/a&gt;的接口，目前已关闭。同时官方的API，发现并没有创建任意群聊的API。对比国外软件，国内的API真的是不开放。国外公司甚至有专门的API Platform团队，负责API开发开放，以及与第三方平台的集成。&lt;/p&gt;&#10;&lt;p&gt;参考连接：&lt;br&gt;&#10;&lt;a class="link" href="https://skpy.t.allofti.me/index.html" target="_blank" rel="noopener"&#10; &gt;SkPy&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Django + Celery处理异步任务/计划任务</title><link>https://courages.us/django-celery%E5%A4%84%E7%90%86%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1-%E8%AE%A1%E5%88%92%E4%BB%BB%E5%8A%A1/</link><pubDate>Fri, 03 May 2019 09:33:31 +0800</pubDate><guid>https://courages.us/django-celery%E5%A4%84%E7%90%86%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1-%E8%AE%A1%E5%88%92%E4%BB%BB%E5%8A%A1/</guid><description>&lt;p&gt;在Web开发的过程中，难免有一些操作是耗时任务，有时候我们不想阻塞Web进程，希望提交到后台处理，有结果了再通知前端；有时候用户不需要实时结果，可以异步处理的，比如发送邮件通知；有时候我们希望定时执行某些任务，复用已有的一些Web代码。对于第一种情况，可以是RPC或调用其他接口处理；第二种情况则是放入队列，由后台进程异步处理；第三种情况可以是在定时任务内处理，也可以是触发消息放入队列，由后台进程任务处理，同第二种情况。对于第一种情况，也可以是放入队列由后台进程处理，Web前端，定时轮询队列/接口是否有结果。这样三种情况都可以统一为一种情况，即不同来源事件（用户/定时器）触发消息，放入队列由后台任务进程异步处理，异步查询结果。&lt;br&gt;&#10;之前的一个Python项目即类似。不管代码是PHP还是Python思想都是类似，只是不同语言有不同工具/优势来处理。Web前端展示统计报表，后台进程定时查询&lt;a class="link" href="https://courages.us/kerberous%e8%ae%a4%e8%af%81/" target="_blank" rel="noopener"&#10; &gt;Impala&lt;/a&gt;，分析统计数据；Web前端也可以触发事件比如统计、发送邮件报告等，后台进程监听并处理。Web前端选择&lt;a class="link" href="https://www.djangoproject.com/" target="_blank" rel="noopener"&#10; &gt;Django&lt;/a&gt;，是Python写的一个MVT框架，提供了登录认证、管理后台模块，还有命令行助手工具可以生成项目，易于快速搭建并扩展Web站点。后台任务处理选择&lt;a class="link" href="http://www.celeryproject.org/" target="_blank" rel="noopener"&#10; &gt;Celery&lt;/a&gt;，是Python写的一个分布式的任务处理平台，支持各种消息队列，比如RabbbitMQ、Redis，并提供&lt;a class="link" href="https://flower.readthedocs.io/en/latest/" target="_blank" rel="noopener"&#10; &gt;Flower&lt;/a&gt;监控工具。Django本身是一个Web框架，生产环境最好使用性能更好的HTTP服务器，&lt;a class="link" href="https://gunicorn.org/" target="_blank" rel="noopener"&#10; &gt;Gunicorn&lt;/a&gt;是Python写的一个WSGI HTTP服务器，用来监听HTTP请求，调用Django。Gunicorn前端最好使用Nginx来做代理，分发请求，结构如下：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/05/qrd.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="525px" data-flex-grow="218" height="137" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/05/qrd-300x137.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;安装Python 3和Django，并生成项目框架代码。注意：由于机器上面本来就有Pyton 2.7，所以要重命名下。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y install yum-utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y groupinstall development&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install zlib-devel bzip2-devel openssl-devel ncurese-devel expat-devel gdbm-devel readline-devel sqlite-devel libffi-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://www.python.org/ftp/python/3.6.2/Python-3.6.2.tar.xz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar Jxvf Python-3.6.2.tar.xz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mv Python-3.6.2 /opt/Python-3.6.2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd /opt/Python-3.6.2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --enable-shared --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local/python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/ld.so.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/python3/lib/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/sbin/ldconfig -v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ln -s /usr/local/python3/bin/python3.6 /usr/bin/python3.6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ln -s /usr/bin/python3.6 /usr/bin/python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ln -s /usr/local/python3/bin/python3.6 /usr/bin/python&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install Django&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 -m django --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ln -s /usr/local/python3/bin/django-admin /usr/bin/django-admin/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd /home/rc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;django-admin startproject qrd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd qrd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 manage.py startapp master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim qrd/settings.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑settings.py，监听相应域名、IP的请求&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ALLOWED_HOSTS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;dev.example.com&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;10.1.*.*]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;INSTALLED_APPS = [&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;django.contrib.admin&lt;span style="color:#e6db74"&gt;&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;django.contrib.auth&lt;span style="color:#e6db74"&gt;&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;master&lt;span style="color:#e6db74"&gt;&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;django.contrib.contenttypes&lt;span style="color:#e6db74"&gt;&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;django.contrib.sessions&lt;span style="color:#e6db74"&gt;&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;django.contrib.messages&lt;span style="color:#e6db74"&gt;&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#39;&lt;/span&gt;django.contrib.staticfiles&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 manage.py runserver 0:80&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装Gunicorn&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pip3 install gunicorn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pip3 install greenlet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pip3 install ConfigParser&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ln -s /usr/local/python3/bin/gunicorn /usr/bin/gunicorn&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd ~/qrd/qrd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ gunicorn -w &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; qrd.wsgi --bind unix:/tmp/gunicorn.sock&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/systemd/system/gunicorn.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建Gunicorn服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Unit&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;gunicorn daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;After&lt;span style="color:#f92672"&gt;=&lt;/span&gt;network.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Service&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Group&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WorkingDirectory&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/rc/qrd/qrd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind unix:/tmp/gunicorn.sock qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Install&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WantedBy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开机启动&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start gunicorn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable gunicorn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#systemctl stop gunicorn&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来安装Nginx&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/nginx/conf.d/default.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置Nginx与Gunicorn通过UNIX Sockect通信&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name localhost;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#charset koi8-r;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#access_log /var/log/nginx/host.access.log main;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#location / {&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# root /usr/share/nginx/html;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# index index.html index.htm;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://unix:/tmp/gunicorn.sock;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动Nginx&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装MySQL及RabbitMQ&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install mysql-community-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install mysqlclient&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install rabbitmq-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rabbitmq-server -detached&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rabbitmqctl status&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建RabbitMQ vhost&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rabbitmqctl add_user qrdweb &amp;lt;password&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating user &lt;span style="color:#e6db74"&gt;&amp;#34;qrdweb&amp;#34;&lt;/span&gt; ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...done.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rabbitmqctl add_vhost qrdweb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating vhost &lt;span style="color:#e6db74"&gt;&amp;#34;qrdweb&amp;#34;&lt;/span&gt; ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...done.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rabbitmqctl set_user_tags qrdweb management&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Setting tags &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; user &lt;span style="color:#e6db74"&gt;&amp;#34;qrdweb&amp;#34;&lt;/span&gt; to &lt;span style="color:#f92672"&gt;[&lt;/span&gt;management&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...done.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rabbitmqctl set_permissions -p qrdweb qrdweb &lt;span style="color:#e6db74"&gt;&amp;#34;.*&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;.*&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;.*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Setting permissions &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; user &lt;span style="color:#e6db74"&gt;&amp;#34;qrdweb&amp;#34;&lt;/span&gt; in vhost &lt;span style="color:#e6db74"&gt;&amp;#34;qrdweb&amp;#34;&lt;/span&gt; ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...done.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ netstat -apn | grep rabbitmq&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rabbitmqctl status&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装Celery&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install celery&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ln -s /usr/local/python3/bin/celery /usr/bin/celery&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试Celery的异步任务worker及计划任务schedule&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd /home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dashboard db.sqlite3 manage.py master qrd static&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ celery -A qrd worker -l info&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/python3/lib/python3.6/site-packages/celery/platforms.py:795: RuntimeWarning: You&lt;span style="color:#e6db74"&gt;&amp;#39;re running the worker with superuser privileges: this is&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;absolutely not recommended!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Please specify a different user using the -u option.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;User information: uid=0 euid=0 gid=0 egid=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; uid=uid, euid=euid, gid=gid, egid=egid,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; -------------- celery@localhost.localdomain v4.1.0 (latentcall)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;---- **** -----&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;--- * *** * -- Linux-3.10.0-693.2.2.el7.x86_64-x86_64-with-centos-7.4.1708-Core 2017-09-22 08:19:39&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;-- * - **** ---&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;- ** ---------- [config]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;- ** ---------- .&amp;gt; app: qrd:0x7fda62e705c0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;- ** ---------- .&amp;gt; transport: amqp://qrdweb:**@localhost:5672/qrdweb&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;- ** ---------- .&amp;gt; results: disabled://&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;- *** --- * --- .&amp;gt; concurrency: 1 (prefork)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;-- ******* ---- .&amp;gt; task events: OFF (enable -E to monitor tasks in this worker)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;--- ***** -----&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; -------------- [queues]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; .&amp;gt; celery exchange=celery(direct) key=celery&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[tasks]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . dashboard.tasks.debug_task&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:19:39,769: INFO/MainProcess] Connected to amqp://qrdweb:**@127.0.0.1:5672/qrdweb&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:19:39,781: INFO/MainProcess] mingle: searching for neighbors&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:19:40,811: INFO/MainProcess] mingle: all alone&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:19:40,860: WARNING/MainProcess] /usr/local/python3/lib/python3.6/site-packages/celery/fixups/django.py:202: UserWarning: Using settings.DEBUG leads to a memory leak, never use this setting in production environments!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; warnings.warn(&amp;#39;&lt;/span&gt;Using settings.DEBUG leads to a memory leak, never &lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:19:40,860: INFO/MainProcess] celery@localhost.localdomain ready.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:20:55,023: INFO/MainProcess] Received task: dashboard.tasks.debug_task[71e6c0e1-92e1-494e-b5e9-163eeb7bd24e]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:20:55,027: INFO/ForkPoolWorker-1] Task dashboard.tasks.debug_task[71e6c0e1-92e1-494e-b5e9-163eeb7bd24e] succeeded in 0.001253978000022471s: &amp;#39;&lt;/span&gt;debug_task&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:22:21,179: INFO/MainProcess] Received task: dashboard.tasks.debug_task[b81fe9a0-1725-4702-ba0e-13196c9b5977]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-22 08:22:21,180: INFO/ForkPoolWorker-1] Task dashboard.tasks.debug_task[b81fe9a0-1725-4702-ba0e-13196c9b5977] succeeded in 0.00018433199147693813s: &amp;#39;&lt;/span&gt;debug_task&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$ celery -A qrd beat -l info -s /tmp/celerybeat-schedule&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;celery beat v4.1.0 (latentcall) is starting.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;__ - ... __ - _&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;LocalTime -&amp;gt; 2017-09-24 04:20:37&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Configuration -&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . broker -&amp;gt; amqp://qrdweb:**@localhost:5672/qrdweb&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . loader -&amp;gt; celery.loaders.app.AppLoader&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . scheduler -&amp;gt; celery.beat.PersistentScheduler&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . db -&amp;gt; /tmp/celerybeat-schedule&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . logfile -&amp;gt; [stderr]@%INFO&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; . maxinterval -&amp;gt; 5.00 minutes (300s)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-24 04:20:37,823: INFO/MainProcess] beat: Starting...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-24 04:20:37,866: INFO/MainProcess] Scheduler: Sending due task add every 10 (qrd.celery.test)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-24 04:20:47,856: INFO/MainProcess] Scheduler: Sending due task add every 10 (qrd.celery.test)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-24 04:20:57,858: INFO/MainProcess] Scheduler: Sending due task add every 10 (qrd.celery.test)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2017-09-24 04:20:57,861: INFO/MainProcess] Scheduler: Sending due task qrd.celery.test(&amp;#39;&lt;/span&gt;world&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;qrd.celery.test&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2017-09-24 04:21:07,858: INFO/MainProcess&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Scheduler: Sending due task add every &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;qrd.celery.test&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2017-09-24 04:21:17,859: INFO/MainProcess&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Scheduler: Sending due task add every &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;qrd.celery.test&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行成功，可以使用Supervisord来守护监控Celery的运行，参考&lt;a class="link" href="https://courages.us/%e4%bd%bf%e7%94%a8superviosr-%e7%ae%a1%e7%90%86%e7%9b%91%e6%8e%a7%e8%bf%9b%e7%a8%8b/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;Django项目结果如下&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/05/Screen-Shot-2019-05-03-at-8.42.49-AM.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="167px" data-flex-grow="69" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/05/Screen-Shot-2019-05-03-at-8.42.49-AM-209x300.png" width="209"&gt;&lt;/a&gt;&lt;br&gt;&#10;先配置Celery使用RabbitMQ作为Broker，使用Django DB来保存调用结果settings.py&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; configparser &lt;span style="color:#f92672"&gt;import&lt;/span&gt; RawConfigParser&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#https://code.djangoproject.com/wiki/SplitSettings&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;config &lt;span style="color:#f92672"&gt;=&lt;/span&gt; RawConfigParser()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;config&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read(&lt;span style="color:#e6db74"&gt;&amp;#39;/home/qrd/setting/settings.ini&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;STATIC_URL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/static/&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;STATIC_ROOT &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;join(BASE_DIR, &lt;span style="color:#e6db74"&gt;&amp;#39;static&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CELERY_BROKER_URL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;amqp://usr:pwd@localhost:5672/qrdweb&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CELERY_RESULT_BACKEND &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;django-db&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在Django项目下创建&lt;a class="link" href="http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html" target="_blank" rel="noopener"&#10; &gt;celery.py文件&lt;/a&gt;，&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; __future__ &lt;span style="color:#f92672"&gt;import&lt;/span&gt; absolute_import, unicode_literals&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; celery &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Celery&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; celery.schedules &lt;span style="color:#f92672"&gt;import&lt;/span&gt; crontab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# set the default Django settings module for the &amp;#39;celery&amp;#39; program.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;setdefault(&lt;span style="color:#e6db74"&gt;&amp;#39;DJANGO_SETTINGS_MODULE&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;qrd.settings&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Celery(&lt;span style="color:#e6db74"&gt;&amp;#39;qrd&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Using a string here means the worker doesn&amp;#39;t have to serialize&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# the configuration object to child processes.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# - namespace=&amp;#39;CELERY&amp;#39; means all celery-related configuration keys&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# should have a `CELERY_` prefix.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config_from_object(&lt;span style="color:#e6db74"&gt;&amp;#39;django.conf:settings&amp;#39;&lt;/span&gt;, namespace&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;CELERY&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Load task modules from all registered Django app configs.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;autodiscover_tasks()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;beat_schedule &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;hue-tasks-debug_task&amp;#39;&lt;/span&gt;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;task&amp;#39;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;hue.tasks.debug_task&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;schedule&amp;#39;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10.0&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;args&amp;#39;&lt;/span&gt;: ()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;并且在__init__.py引入Celery即可集成&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; __future__ &lt;span style="color:#f92672"&gt;import&lt;/span&gt; absolute_import, unicode_literals&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# This will make sure the app is always imported when&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Django starts so that shared_task will use this app.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; .celery &lt;span style="color:#f92672"&gt;import&lt;/span&gt; app &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; celery_app&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;__all__ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;celery_app&amp;#39;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Django的异步任务只能定义在各个app的task.py文件里，比如qrd.hue.tasks定义了一个定时任务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; celery &lt;span style="color:#f92672"&gt;import&lt;/span&gt; task&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;debug_task&lt;/span&gt;():&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#print(arg)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;debug_task&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以在其模块里面调用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; tasks &lt;span style="color:#f92672"&gt;import&lt;/span&gt; debug_task&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;save&lt;/span&gt;(data):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; debug_task&lt;span style="color:#f92672"&gt;.&lt;/span&gt;delay()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;顺便推荐一个Bootstrap管理后台模板：&lt;a class="link" href="https://github.com/ColorlibHQ/gentelella" target="_blank" rel="noopener"&#10; &gt;gentelella&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://funhacks.net/2016/12/13/celery/" target="_blank" rel="noopener"&#10; &gt;异步任务神器 Celery&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://juejin.im/post/5b588b8c6fb9a04f834655a6" target="_blank" rel="noopener"&#10; &gt;Django配置celery执行异步任务和定时任务&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://medium.com/@genchilu/%E6%B7%BA%E8%AB%87-gunicorn-%E5%90%84%E5%80%8B-worker-type-%E9%81%A9%E5%90%88%E7%9A%84%E6%83%85%E5%A2%83-490b20707f28" target="_blank" rel="noopener"&#10; &gt;淺談 Gunicorn 各個 worker type 適合的情境&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>CentOS 7上安装OpenVPN</title><link>https://courages.us/centos-7%E4%B8%8A%E5%AE%89%E8%A3%85openvpn/</link><pubDate>Wed, 17 Apr 2019 16:19:29 +0800</pubDate><guid>https://courages.us/centos-7%E4%B8%8A%E5%AE%89%E8%A3%85openvpn/</guid><description>&lt;p&gt;之前做的一些树莓派机器因为分布分散，不好远程调试，最近看了&lt;a class="link" href="https://www.cyberciti.biz/faq/centos-7-0-set-up-openvpn-server-in-5-minutes/" target="_blank" rel="noopener"&#10; &gt;CentOS 7.0 Set Up OpenVPN Server In 5 Minutes&lt;/a&gt;，决定备份一下。&lt;br&gt;&#10;首先需要有一台公网服务器，比如阿里云、腾讯云服务器，以便这些设备能连接上。阿里云、腾讯云的服务器外部IP并不是直接绑定在你的服务器上的，而是NAT转发到服务器上的，这与Linode不一样，虽然可以方便换IP。查看服务器公网IP，也可以在云管理后台查看&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip a show eth0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dig +short myip.opendns.com @resolver1.opendns.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;{ print $2}&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是一键安装脚步&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://raw.githubusercontent.com/Angristan/openvpn-install/master/openvpn-install.sh -O centos7-vpn.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x centos7-vpn.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./centos7-vpn.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Welcome to the OpenVPN installer!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The git repository is available at: https://github.com/angristan/openvpn-install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I need to ask you a few questions before starting the setup.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You can leave the default options and just press enter &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you are ok with them.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I need to know the IPv4 address of the network interface you want OpenVPN listening to.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Unless your server is behind NAT, it should be your public IPv4 address.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IP address: 10.0.2.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;It seems this server is behind NAT. What is its public IPv4 address or hostname?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;We need it &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; the clients to connect to the server.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Public IPv4 address or hostname: 110.*.*.*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Checking &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; IPv6 connectivity...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Your host does not appear to have IPv6 connectivity.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Do you want to enable IPv6 support &lt;span style="color:#f92672"&gt;(&lt;/span&gt;NAT&lt;span style="color:#f92672"&gt;)&lt;/span&gt;? &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: n&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What port &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; you want OpenVPN to listen to?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Default: &lt;span style="color:#ae81ff"&gt;1194&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Custom&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Random &lt;span style="color:#f92672"&gt;[&lt;/span&gt;49152-65535&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Port choice &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-3&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What protocol &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; you want OpenVPN to use?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;UDP is faster. Unless it is not available, you shouldn&lt;span style="color:#e6db74"&gt;&amp;#39;t use TCP.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 1) UDP&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 2) TCP&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Protocol [1-2]: 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;What DNS resolvers do you want to use with the VPN?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 1) Current system resolvers (from /etc/resolv.conf)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 2) Self-hosted DNS Resolver (Unbound)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 3) Cloudflare (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 4) Quad9 (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 5) Quad9 uncensored (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 6) FDN (France)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 7) DNS.WATCH (Germany)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 8) OpenDNS (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 9) Google (Anycast: worldwide)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 10) Yandex Basic (Russia)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; 11) AdGuard DNS (Russia)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;DNS [1-10]: 3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Do you want to use compression? It is not recommended since the VORACLE attack make use of it.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Enable compression? [y/n]: n&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Do you want to customize encryption settings?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Unless you know what you&amp;#39;&lt;/span&gt;re doing, you should stick with the default parameters provided by the script.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Note that whatever you choose, all the choices presented in the script are safe. &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Unlike OpenVPN&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;s defaults&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;See https://github.com/angristan/openvpn-install#security-and-encryption to learn more.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Customize encryption settings? &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: n&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Okay, that was all I needed. We are ready to setup your OpenVPN server now.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You will be able to generate a client at the end of the installation.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Press any key to &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个脚本省掉了许许多多配置，基本上按照默认一路enter就可以了，唯一需要输入的就是你的公网IP和生成的OpenVPN客户端连接文件名字，比如client.ovpn&lt;br&gt;&#10;然后启动服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl stop openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl restart openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl status openvpn@server&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看生成的服务器配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# cat /etc/openvpn/server.conf&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;port &lt;span style="color:#ae81ff"&gt;1194&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proto udp6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dev tun&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;group nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;persist-key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;persist-tun&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;keepalive &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;topology subnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server 10.8.0.0 255.255.255.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ifconfig-pool-persist ipp.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#client-to-client&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;dhcp-option DNS 1.0.0.1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;dhcp-option DNS 1.1.1.1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;redirect-gateway def1 bypass-dhcp&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#server-ipv6 fd42:42:42:42::/112&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#tun-ipv6&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push tun-ipv6&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;route-ipv6 2000::/3&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#push &amp;#34;redirect-gateway ipv6&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dh none&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ecdh-curve prime256v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-crypt tls-crypt.key &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;crl-verify crl.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ca ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cert server_Yfej6xnJrDu3vs6K.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;key server_Yfej6xnJrDu3vs6K.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth SHA256&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cipher AES-128-GCM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ncp-ciphers AES-128-GCM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-version-min 1.2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tls-cipher TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;status /var/log/openvpn/status.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;verb &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;10.8.0.0是默认的组网网段，可以改成别的。腾讯云并不支持IPV6，注释掉。push “dhcp-option DNS 1.0.0.1″是推送DNS服务器给客户端。push “redirect-gateway def1 bypass-dhcp”是重定向客户端所有流量到服务器，建议按需添加需要互访的子网段（默认只有10.8.0.0可以互相访问)，否则所有流量重定向，可能会引起连接问题，比如ssh腾讯云服务器公网22端口进不去。Push和Route还有高级应用，建议参考&lt;a class="link" href="https://openvpn.net/community-resources/how-to/" target="_blank" rel="noopener"&#10; &gt;OpenVPN: 2x HOW TO&lt;/a&gt;&lt;br&gt;&#10;查看连接状况。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;journalctl --identifier openvpn -f&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置腾讯云服务器安全组，开放1194端口&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/04/1194incomming.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="1333px" data-flex-grow="555" height="54" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/04/1194incomming-300x54.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2019/04/1194outcomming.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="1384px" data-flex-grow="576" height="52" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2019/04/1194outcomming-300x52.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;将刚才生成的client.ovpn下载下来，mac上双击，使用Tunnelblick打开导入即可。但是使用最新的OpenVPN 2.6提示连不上， 报错：tls-crypt unwrap error: packet too short。&lt;br&gt;&#10;在Linux上安装OpenVPN，启动连接&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install openvpn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp client.ovpn /etc/openvpn/client.conf &lt;span style="color:#75715e"&gt;#一定要复制到这里&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openvpn --client --config /etc/openvpn/client.conf &lt;span style="color:#75715e"&gt;#测试一下&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start openvpn@client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable openvpn@client&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ping 10.8.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip route&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果有问题的话，可以查看iptable配置、网络及进程&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /etc/iptables/add-openvpn-rules.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A INPUT -i tun0 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A FORWARD -i tun0 -o eth0 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -A INPUT -i eth0 -p udp --dport &lt;span style="color:#ae81ff"&gt;1194&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;iptables -t nat -L -n -v &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;net.ipv4.ip_forward&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;netstat -tulpn | grep :1194&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps aux | grep openvpn&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当再一次运行脚本的时候，会提示是否创建新用户配置，注意不同用户不能共享同一个配置。这里创建的用户可以是支持用户名密码也可以是无账号密码的。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@tc ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./centos7-vpn.sh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Welcome to OpenVPN-install!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The git repository is available at: https://github.com/angristan/openvpn-install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;It looks like OpenVPN is already installed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;What &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; you want to &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Add a new user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Revoke existing user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Remove OpenVPN&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 4&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Select an option &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-4&lt;span style="color:#f92672"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;连上OpenVPN服务器都处于同一个网络了，可以使用内部IP访问。现在使用docker来部署OpenVPN服务也很方便，比如&lt;a class="link" href="https://hub.docker.com/r/mdns/rancher-openvpn" target="_blank" rel="noopener"&#10; &gt;rancher-openvpn&lt;/a&gt;，支持LDAP验证。&lt;br&gt;&#10;如果是两个及以上的局域网互通，可以使用&lt;a class="link" href="https://www.openswan.org/" target="_blank" rel="noopener"&#10; &gt;Openswan&lt;/a&gt;建立虚拟网络连接。&lt;br&gt;&#10;更新：发现resin更新成了&lt;a class="link" href="https://www.balena.io/" target="_blank" rel="noopener"&#10; &gt;balena&lt;/a&gt;，免费支持10台设备，并且开放了IOT相关的&lt;a class="link" href="https://www.balena.io/open/docs/getting-started" target="_blank" rel="noopener"&#10; &gt;系统、软件&lt;/a&gt;。&lt;br&gt;&#10;发现一个新的组网服务&lt;a class="link" href="https://www.zerotier.com/" target="_blank" rel="noopener"&#10; &gt;zerotier&lt;/a&gt;，可以快速的创建属于自己的私有网络。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-centos-7" target="_blank" rel="noopener"&#10; &gt;How To Set Up and Configure an OpenVPN Server on CentOS 7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.linode.com/docs/networking/vpn/tunnel-your-internet-traffic-through-an-openvpn-server/" target="_blank" rel="noopener"&#10; &gt;Tunnel Your Internet Traffic Through an OpenVPN Server&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://wiki.teltonika.lt/view/OpenVPN_configuration_examples" target="_blank" rel="noopener"&#10; &gt;OpenVPN configuration examples&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://help.aliyun.com/knowledge_detail/42521.html" target="_blank" rel="noopener"&#10; &gt;云服务器 ECS Linux CentOS OpenVPN 配置概述&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://yq.aliyun.com/articles/629131" target="_blank" rel="noopener"&#10; &gt;使用OpenVPN搞定远程办公&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.cnblogs.com/huangweimin/articles/7700892.html" target="_blank" rel="noopener"&#10; &gt;使用openvpn打通两个异地网络&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://linuxpitstop.com/install-openswan-and-create-site-to-site-vpn-on-centos-linux/" target="_blank" rel="noopener"&#10; &gt;How To Install Openswan And Create Site-to-Site VPN On CentOS 7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.convisoappsec.com/setting-up-an-ipsec-vpn-using-openswan-in-cloud-environments/" target="_blank" rel="noopener"&#10; &gt;Setting up an IPSEC VPN using OpenSwan in cloud environments&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup" target="_blank" rel="noopener"&#10; &gt;Openswan L2TP/IPsec VPN client setup&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/%e5%9c%a8raspberry-pi%e4%b8%8a%e9%9d%a2%e8%bf%90%e8%a1%8cdocker/" target="_blank" rel="noopener"&#10; &gt;在Raspberry Pi上面运行Docker&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://einverne.github.io/post/2018/06/zerotier.html" target="_blank" rel="noopener"&#10; &gt;使用 Zerotier 组建虚拟局域网实现内网穿透&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://askubuntu.com/questions/612840/adding-route-on-client-using-openvpn" target="_blank" rel="noopener"&#10; &gt;trying to route between two openvpn clients&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://openvpn.net/vpn-server-resources/site-to-site-routing-explained-in-detail/" target="_blank" rel="noopener"&#10; &gt;Site-to-site VPN routing explained in detail&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Let’s encrypt</title><link>https://courages.us/lets-encrypt/</link><pubDate>Sun, 11 Feb 2018 15:21:18 +0800</pubDate><guid>https://courages.us/lets-encrypt/</guid><description>&lt;p&gt;最近域名主机双双到期了，原来的服务商建议域名迁出，于是转移到了Godaddy，过程很顺利。主机迁到了linode，一个是因为它便宜，另一个是因为想给自己的网站加个SSL证书。&lt;br&gt;&#10;首先是服务器环境Apache, PHP, MaraiDB(MySQL)的配置。 &lt;a class="link" href="https://linode.com/docs/getting-started/" target="_blank" rel="noopener"&#10; &gt;linode 创建主机&lt;/a&gt;很简单，点点就好了，然后可以去启动机器，设置SSH访问。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install httpd php php-cli php-mbstring php-pdo php-mysql php-gd php-tidy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动Apache&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start httpd.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable httpd.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后直接访问你的服务器ip，可以看到默认的欢迎界面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip addr show eth0 | grep inet | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{ print $2; }&amp;#39;&lt;/span&gt; | sed &lt;span style="color:#e6db74"&gt;&amp;#39;s/\/.*$//&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl 1.139.x.x&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CentOS 7目前默认不提供Mysql Server，而是&lt;a class="link" href="https://mariadb.org/" target="_blank" rel="noopener"&#10; &gt;Mariadb&lt;/a&gt;。MySQL的命令行仍然可以使用并兼容， PHP仍然可以使用PDO及MySQL扩展访问它。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install mariadb-server mariadb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start mariadb&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后设置管理员密码及安全设置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysql_secure_installation&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开机启动Mariadb服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl enable mariadb.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以在/var/www/html目录下创建一个测试脚本来验证安装情况&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;phpinfo&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;WordPress则是从原本的数据库全部导出，文件全部打包回来。&lt;br&gt;&#10;在Linode上创建对应的数据库，用户及导入脚本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MariaDB &lt;span style="color:#f92672"&gt;[(&lt;/span&gt;none&lt;span style="color:#f92672"&gt;)]&lt;/span&gt;&amp;gt; CREATE database courages_wordpress;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MariaDB &lt;span style="color:#f92672"&gt;[(&lt;/span&gt;none&lt;span style="color:#f92672"&gt;)]&lt;/span&gt;&amp;gt; CREATE USER courages_wp IDENTIFIED BY &lt;span style="color:#e6db74"&gt;&amp;#39;*************&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MariaDB &lt;span style="color:#f92672"&gt;[(&lt;/span&gt;none&lt;span style="color:#f92672"&gt;)]&lt;/span&gt;&amp;gt; grant all privileges on courages_wordpress.* to courages_wp@localhost identified by &lt;span style="color:#e6db74"&gt;&amp;#39;*************&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;导入数据库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysql -uroot -p courages_wordpress &amp;lt; /tmp/wordpress.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将文件解压并复制到/var/www/html目录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -xzvf backup.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp -R backup/public_html/* /var/www/html/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chown -R apache:apache /var/www/html&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改Apache设置AllowOverride 为all，以便支持WordPress的链接重定向。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/httpd/conf/httpd.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;Directory &lt;span style="color:#e6db74"&gt;&amp;#34;/var/www/html&amp;#34;&lt;/span&gt;&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Possible values for the Options directive are &amp;#34;None&amp;#34;, &amp;#34;All&amp;#34;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# or any combination of:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Note that &amp;#34;MultiViews&amp;#34; must be named *explicitly* --- &amp;#34;Options All&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# doesn&amp;#39;t give it to you.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The Options directive is both complicated and important. Please see&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# http://httpd.apache.org/docs/2.4/mod/core.html#options&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# for more information.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Options Indexes FollowSymLinks&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# AllowOverride controls what directives may be placed in .htaccess files.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# It can be &amp;#34;All&amp;#34;, &amp;#34;None&amp;#34;, or any combination of the keywords:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Options FileInfo AuthConfig Limit&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AllowOverride All&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Controls who can get stuff from this server.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Require all granted&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/Directory&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启Apache&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl restart httpd.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在linode的DNS manager那里新增一个新的domain，在服务器列表里面选中对应的服务器就可以了，然后就可以看到对应的域名解析信息。&lt;br&gt;&#10;域名转移会要求一个key，从原注册商那里解锁并获得，在Godday输入Key后，它会发邮件与你确认，然后将DNS域名服务器改为linode的域名服务器就好了。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://letsencrypt.org/getting-started/" target="_blank" rel="noopener"&#10; &gt;Let’s Encrypt&lt;/a&gt;提供免费90天的SSL证书，如果证书到期了就需要再次更新下。如果你有shell权限，它推荐使用&lt;a class="link" href="https://certbot.eff.org/" target="_blank" rel="noopener"&#10; &gt;Cerbot&lt;/a&gt;来安装和更新证书。CentOS 7 + Apache的安装非常简单。首先安装EPEL源，要不然找不到对应的安装包&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install epel-release&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install certbot-apache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot --authenticator webroot --installer apache&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置一下域名，网站目录及域名重定向&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Saving debug log to /var/log/letsencrypt/letsencrypt.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Plugins selected: Authenticator webroot, Installer apache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Enter email address &lt;span style="color:#f92672"&gt;(&lt;/span&gt;used &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; urgent renewal and security notices&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Enter &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &amp;lt;email@example.com&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: acme-v01.api.letsencrypt.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please read the Terms of Service at&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;agree in order to register with the ACME server at&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://acme-v01.api.letsencrypt.org/directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;A&lt;span style="color:#f92672"&gt;)&lt;/span&gt;gree/&lt;span style="color:#f92672"&gt;(&lt;/span&gt;C&lt;span style="color:#f92672"&gt;)&lt;/span&gt;ancel: A&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Would you be willing to share your email address with the Electronic Frontier&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Foundation, a founding partner of the Let&lt;span style="color:#e6db74"&gt;&amp;#39;s Encrypt project and the non-profit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;organization that develops Certbot? We&amp;#39;&lt;/span&gt;d like to send you email about EFF and&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;our work to encrypt the web, protect its users and defend digital rights.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;Y&lt;span style="color:#f92672"&gt;)&lt;/span&gt;es/&lt;span style="color:#f92672"&gt;(&lt;/span&gt;N&lt;span style="color:#f92672"&gt;)&lt;/span&gt;o: Y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting new HTTPS connection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: supporters.eff.org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No names were found in your configuration files. Please enter in your domain&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name&lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;comma and/or space separated&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Enter &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Obtaining a new certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Performing the following challenges:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http-01 challenge &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Input the webroot &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; courages.us: &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Enter &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: /var/www/html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; verification...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Cleaning up challenges&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;We were unable to find a vhost with a ServerName or Address of courages.us.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Which virtual host would you like to choose?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;note: conf files with multiple vhosts are not yet supported&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1: ssl.conf | | HTTPS | Enabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Press &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;enter&lt;span style="color:#f92672"&gt;]&lt;/span&gt; to confirm the selection &lt;span style="color:#f92672"&gt;(&lt;/span&gt;press &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Deploying Certificate &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; courages.us to VirtualHost /etc/httpd/conf.d/ssl.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1: No redirect - Make no further changes to the webserver configuration.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2: Redirect - Make all requests redirect to secure HTTPS access. Choose this &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;new sites, or &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you&lt;span style="color:#e6db74"&gt;&amp;#39;re confident your site works on HTTPS. You can undo this&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;change by editing your web server&amp;#39;&lt;/span&gt;s configuration.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Select the appropriate number &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1-2&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;enter&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;press &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt; to cancel&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Created redirect file: le-redirect-courages.us.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rollback checkpoint is empty &lt;span style="color:#f92672"&gt;(&lt;/span&gt;no changes made?&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Congratulations! You have successfully enabled https://courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You should test your configuration at:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://www.ssllabs.com/ssltest/analyze.html?d&lt;span style="color:#f92672"&gt;=&lt;/span&gt;courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在浏览器访问一下域名即有小绿钥匙。可以在/etc/httpd/conf.d/ssl.conf查看相应的SSL证书配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;VirtualHost _default_:443&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ServerName courages.us&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSLCertificateFile /etc/letsencrypt/live/courages.us/cert.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSLCertificateKeyFile /etc/letsencrypt/live/courages.us/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Include /etc/letsencrypt/options-ssl-apache.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSLCertificateChainFile /etc/letsencrypt/live/courages.us/chain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/VirtualHost&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于证书在90天后即将失效，可以加入crontab自动更新&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;certbot renew --dry-run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;crontab -e&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0,12 * * * python -c &lt;span style="color:#e6db74"&gt;&amp;#39;import random; import time; time.sleep(random.random() * 3600)&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; certbot renew &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外一种更新证书的方法是使用&lt;a class="link" href="https://github.com/acmesh-official/acme.sh" target="_blank" rel="noopener"&#10; &gt;acme.sh&lt;/a&gt;，不依赖python，同样支持DNS验证，并且还可以获取其他CA颁发的证书，比如&lt;a class="link" href="https://zerossl.com/" target="_blank" rel="noopener"&#10; &gt;ZeroSSL&lt;/a&gt;。&lt;br&gt;&#10;安装acme。sh脚本非常简单&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ curl https://get.acme.sh | sh -s email&lt;span style="color:#f92672"&gt;=&lt;/span&gt;llitllie@163.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% Total % Received % Xferd Average Speed Time Time Time Current&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dload Upload Total Spent Left Speed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;608&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; --:--:-- 0:00:01 --:--:-- &lt;span style="color:#ae81ff"&gt;608&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% Total % Received % Xferd Average Speed Time Time Time Current&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Dload Upload Total Spent Left Speed&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; 216k &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; 216k &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 104k &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 0:00:02 0:00:02 --:--:-- 104k&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:22 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing from online archive.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:22 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Downloading https://github.com/acmesh-official/acme.sh/archive/master.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:25 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Extracting master.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; It is recommended to install socat first.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; We use socat &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; standalone server &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you use standalone mode.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; If you don&lt;span style="color:#e6db74"&gt;&amp;#39;t use standalone mode, just ignore this warning.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing to /root/.acme.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installed to /root/.acme.sh/acme.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing alias to &amp;#39;&lt;/span&gt;/root/.zshrc&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] OK, Close and reopen your terminal to start using acme.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing alias to &amp;#39;&lt;/span&gt;/root/.cshrc&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:11:26 CST] Installing alias to &amp;#39;&lt;/span&gt;/root/.tcshrc&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing cron job&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:26 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Good, bash is found, so change the shebang to use bash as preferred.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:11:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Install success!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里采用DNS验证获取证书，设置一下&lt;a class="link" href="https://github.com/acmesh-official/acme.sh/wiki/dnsapi" target="_blank" rel="noopener"&#10; &gt;DNS厂商信息&lt;/a&gt;，比如DNSPOD，默认获取ZeroSSL证书，可以通过&lt;a class="link" href="https://github.com/acmesh-official/acme.sh/wiki/Change-default-CA-to-ZeroSSL" target="_blank" rel="noopener"&#10; &gt;–server letsencrypt&lt;/a&gt;切换&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ export DP_Id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;95731&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ export DP_Key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;***&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ acme.sh --issue --dns dns_dp -d example.com -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:24 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Using CA: https://acme.zerossl.com/v2/DV90&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:24 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Create account key ok.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:24 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; No EAB credentials found &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ZeroSSL, let&lt;span style="color:#e6db74"&gt;&amp;#39;s get one&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:29 CST] Registering account: https://acme.zerossl.com/v2/DV90&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] Registered&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] ACCOUNT_THUMBPRINT=&amp;#39;&lt;/span&gt;AY5noJZbSullM7fVQOnluxQJmWiiKJHl0vzVsYwwGsg&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] Creating domain key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] The domain key is here: /root/.acme.sh/example.com_ecc/example.com.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:14:38 CST] Multi domain=&amp;#39;&lt;/span&gt;DNS:example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:39 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Getting domain auth token &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; each domain&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:56 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Getting webroot &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:56 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Getting webroot &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;*.example.com&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:56 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Adding txt value: q-pQccpOPbYbC4h_veQTSvj2OgUpgg9kBUFpms9fa9k &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain: _acme-challenge.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:57 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Adding record&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:14:57 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The txt record is added: Success.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:01 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Let&lt;span style="color:#e6db74"&gt;&amp;#39;s check each DNS record now. Sleep 20 seconds first.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] You can use &amp;#39;&lt;/span&gt;--dnssleep&lt;span style="color:#e6db74"&gt;&amp;#39; to disable public dns checks.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] Checking example.com for _acme-challenge.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:23 CST] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:27 CST] Domain example.com &amp;#39;&lt;/span&gt;_acme-challenge.example.com&lt;span style="color:#e6db74"&gt;&amp;#39; success.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[2023年 04月 07日 星期五 22:15:34 CST] All success, let&amp;#39;&lt;/span&gt;s &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:34 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Verifying: example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:46 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Processing, The CA is processing your order, please just wait. &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1/30&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:51 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:51 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Verifying: *.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:15:55 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Processing, The CA is processing your order, please just wait. &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1/30&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Removing DNS records.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:28 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Removing txt: q-pQccpOPbYbC4h_veQTSvj2OgUpgg9kBUFpms9fa9k &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; domain: _acme-challenge.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:30 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Removed: Success&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:34 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Verify finished, start to sign.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:35 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Lets finalize the order.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:40 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Order status is processing, lets sleep and retry.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:16:40 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Retry after: &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:00 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Downloading cert.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:00 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Le_LinkCert&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;https://acme.zerossl.com/v2/DV90/cert/pcAU9PLEoObR7xYPTb9x7w&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Cert success.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----BEGIN CERTIFICATE-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MIIELzCCA7agAwIBAgIRAOO4Gyu...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QRwR2SSrAlEIeJXua7aYyyEEJQ&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-----END CERTIFICATE-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Your cert is in: /root/.acme.sh/example.com_ecc/example.com.cer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Your cert key is in: /root/.acme.sh/example.com_ecc/example.com.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The intermediate CA cert is in: /root/.acme.sh/example.com_ecc/ca.cer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 22:17:03 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; And the full chain certs is there: /root/.acme.sh/example.com_ecc/fullchain.cer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后安装证书&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ acme.sh --install-cert -d example.com -d &lt;span style="color:#e6db74"&gt;&amp;#34;*.example.com&amp;#34;&lt;/span&gt;--key-file /etc/letsencrypt/live/example.com/privkey.pem --fullchain-file /etc/letsencrypt/live/example.com/chain.pem --reloadcmd &lt;span style="color:#e6db74"&gt;&amp;#34;systemctl restart nginx&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; The domain &lt;span style="color:#e6db74"&gt;&amp;#39;example.com&amp;#39;&lt;/span&gt; seems to have a ECC cert already, lets use ecc cert.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing key to: /etc/letsencrypt/live/example.com/privkey.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Installing full chain to: /etc/letsencrypt/live/example.com/chain.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Run reload cmd: systemctl restart nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2023年 04月 07日 星期五 23:00:13 CST&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Reload success&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以后就可以自动更新了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;➜ ~ crontab -l | grep acme &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;26&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; * * * &lt;span style="color:#e6db74"&gt;&amp;#34;/root/.acme.sh&amp;#34;&lt;/span&gt;/acme.sh --cron --home &lt;span style="color:#e6db74"&gt;&amp;#34;/root/.acme.sh&amp;#34;&lt;/span&gt; &amp;gt; /dev/null&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最近登录后台发现WordPress提示&lt;a class="link" href="https://wordpress.org/support/update-php/" target="_blank" rel="noopener"&#10; &gt;升级到PHP 7.3&lt;/a&gt;，按照它的指示&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用&lt;a class="link" href="https://wordpress.org/plugins/updraftplus/" target="_blank" rel="noopener"&#10; &gt;UpdraftPlus&lt;/a&gt;备份网站和数据库，支持Google Drive, Dropbox&lt;/li&gt;&#10;&lt;li&gt;使用&lt;a class="link" href="https://wordpress.org/plugins/php-compatibility-checker/" target="_blank" rel="noopener"&#10; &gt;PHP Compatibility Checker&lt;/a&gt;检测代码及扩展是否支持升级到PHP 7.3&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在CentOS 7上升级PHP5.4 到PHP 7.3很简单：&lt;br&gt;&#10;首先安装Remi和EPEL仓库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install wget&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -Uvh remi-release-7.rpm &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -Uvh epel-release-latest-7.noarch.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install yum-utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启用remi-php73的源，yum update升级会自动升级PHP及扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# yum-config-manager --enable remi-php73&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# yum repolist&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded plugins: fastestmirror&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loading mirror speeds from cached hostfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * base: mirrors.linode.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * epel: kartolo.sby.datautama.net.id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * extras: mirrors.linode.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * remi-php73: mirror.xeonbd.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * remi-safe: mirror.xeonbd.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * updates: mirrors.linode.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;repo id repo name status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;base/7/x86_64 CentOS-7 - Base 10,019&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;epel/x86_64 Extra Packages &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Enterprise Linux &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - x86_64 13,051&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extras/7/x86_64 CentOS-7 - Extras &lt;span style="color:#ae81ff"&gt;385&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;remi-php73 Remi&lt;span style="color:#e6db74"&gt;&amp;#39;s PHP 7.3 RPM repository for Enterprise Linux 7 - x86_64 305&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;remi-safe Safe Remi&amp;#39;&lt;/span&gt;s RPM repository &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Enterprise Linux &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - x86_64 3,188&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;updates/7/x86_64 CentOS-7 - Updates 1,511&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;repolist: 28,825&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update -y&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查PHP版本，重启Apache&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# php -v&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP 7.3.4 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;cli&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;built: Apr &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2019&lt;/span&gt; 13:48:50&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt; NTS &lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copyright &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1997-2018 The PHP Group&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Zend Engine v3.3.4, Copyright &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1998-2018 Zend Technologies&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@li846-239 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# systemctl restart httpd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以禁用对应PHP版本的源，选择性升级PHP到对应版本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum-config-manager --disable remi-php72&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;顺便升级下php-mcrypt和ZipArchive&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install php-mcrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install php-pecl-zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-centos-7#step-two-%E2%80%94-install-mysql-%5c%28mariadb%5c%29" target="_blank" rel="noopener"&#10; &gt;How To Install Linux, Apache, MySQL, PHP (LAMP) stack On CentOS 7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.liquidweb.com/kb/enable-epel-repository/" target="_blank" rel="noopener"&#10; &gt;How to enable EPEL repository?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://linode.com/docs/security/securing-your-server/" target="_blank" rel="noopener"&#10; &gt;How to Secure Your Server&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://linode.com/docs/security/firewalls/introduction-to-firewalld-on-centos/" target="_blank" rel="noopener"&#10; &gt;Introduction to FirewallD on CentOS&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.mysterydata.com/upgrade-php-5-6-php-7-2-centos-vesta-cp/" target="_blank" rel="noopener"&#10; &gt;How to Upgrade PHP 5.6 to PHP 7.2 on CentOS VestaCP&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Python使用Kerberos认证查询Impala</title><link>https://courages.us/kerberous%E8%AE%A4%E8%AF%81/</link><pubDate>Sun, 22 Oct 2017 11:52:19 +0800</pubDate><guid>https://courages.us/kerberous%E8%AE%A4%E8%AF%81/</guid><description>&lt;p&gt;最近做QoS报告，数据来源于&lt;a class="link" href="https://impala.apache.org/" target="_blank" rel="noopener"&#10; &gt;Impala&lt;/a&gt;，客户端认证采用的是Kerberos。&lt;br&gt;&#10;Impala是&lt;a class="link" href="https://www.cloudera.com/" target="_blank" rel="noopener"&#10; &gt;Cloudera&lt;/a&gt;公司开发并开源的一款基于HDFS/Hbase的MPP SQL引擎，它提供SQL语义，能够查询存储在Hadoop的HDFS和HBase中的PB级大数据。&lt;a class="link" href="https://web.mit.edu/kerberos/" target="_blank" rel="noopener"&#10; &gt;Kerberous&lt;/a&gt;本身是一个网络认证授权协议，借由中心服务器认证，对通信双方的客户端/服务端进行授权而不需要传递双方的密码。Kerberos的认证流程比较有意思，分为&lt;a class="link" href="https://zh.wikipedia.org/wiki/Kerberos" target="_blank" rel="noopener"&#10; &gt;三个阶段&lt;/a&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;客户端认证&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;1 客户端发送自己用户名&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;2 认证服务器返回使用客户端密钥加密的Client/TGS会话密钥和使用票据授权服务器密钥加密的TGT， 包括sessions key，用户信息及有效期&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;3 客户端使用自己的密钥解密出Client/TGS会话密钥&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;服务授权&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;1 客户端发送两条消息：接收到的TGT和所请求的服务ID；使用Client/TGS会话密钥加密的用户ID和时间戳&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;2 票据授权服务器使用自己的密钥解密TGT得到客户端的Client/TGS会话密钥，然后使用它解密出用户ID并进行认证。返回使用所请求服务端密钥加密的client-server票据和使用Client/TGS会话密钥加密的Client/Server会话密钥&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;3 客户端使用Client/TGS会话密钥(Client/TGS Session Key)解密出Client/Server会话密钥&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;服务请求&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;1 客户端发送两条消息：使用所请求服务端密钥加密的client-server票据及使用Client/Server会话密钥加密的用户ID和时间戳&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;2 服务端使用自己的密钥解密client-server票据从而得到Client/Server会话密钥，使用该密钥解密获得用户信息并认证。返回使用Client/Server会话密钥的新时间戳&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;3 客户端使用Client/Server会话密钥解密该消息，认证结束并请求服务&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;4 服务端提供服务&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在CentOS上安装Kerberos&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install krb5-devel pam_krb5 krb5-libs krb5-workstation&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim /etc/krb5.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置KDC，认证服务器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;logging&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FILE:/var/log/krb5libs.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FILE:/var/log/krb5kdc.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;admin_server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FILE:/var/log/kadmind.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;libdefaults&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_realm &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns_lookup_realm &lt;span style="color:#f92672"&gt;=&lt;/span&gt; false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dns_lookup_kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ticket_lifetime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 24h&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;renew_lifetime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; 7d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forwardable &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_tkt_enctypes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc4-hmac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_tgs_enctypes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc4-hmac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;permitted_enctypes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; rc4-hmac&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;realms&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXAMPLE.COM &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default_domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kdc01.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kdc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kdc02.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;admin_server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adc01.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;admin_server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adc02.example.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;domain_realm&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.example.com &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;example.com &lt;span style="color:#f92672"&gt;=&lt;/span&gt; EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost rc&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# kinit abc.xyz@EXAMPLE.COM&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Password &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; abc.xyz@EXAMPLE.COM:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这个配置文件每行前面的空格被删掉，是因为在VirtualBox里面每行开头有莫名其妙的乱码，Linux下并不可见，在EditPlus下面才发现，否则会乱报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kinit: Improper format of Kerberos configuration file &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; initializing Kerberos &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; library&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kinit: Cannot find KDC &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; realm &lt;span style="color:#e6db74"&gt;&amp;#34;EXAMPLE.COM&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; getting initial credentials&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看一下认证的ticket&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@localhost vagrant&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# klist&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Ticket cache: FILE:/tmp/krb5cc_0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Default principal: abc.xyz@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Valid starting Expires Service principal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;09/21/2017 08:30:50 09/21/2017 18:30:50 krbtgt/EXAMPLE.COM@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; renew &lt;span style="color:#66d9ef"&gt;until&lt;/span&gt; 09/28/2017 08:30:42&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个ticket在28号就会过期了，到时候又要输入密码，这样也不便于自动化程序使用。可以使用ktutil创建&lt;a class="link" href="https://kb.iu.edu/d/aumh" target="_blank" rel="noopener"&#10; &gt;keytab文件&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ktutil&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ktutil: addent -password -p abc.xyz@EXAMPLE.COM -k &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; -e RC4-HMAC&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Password &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; abc.xyz@EXAMPLE.COM:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ktutil: wkt abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ktutil: q&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kinit -kt abc.xyz.keytab abc.xyz@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ klist -k abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Keytab name: FILE:abc.xyz.keytab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KVNO Principal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---- --------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; abc.xyz@EXAMPLE.COM&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后便可以使用kinit自动更新ticket了。注意，如果更换了密码，需要重新生成新的keytab。&lt;br&gt;&#10;另外，相同用户生成的授权ticket在任意一台机器上都是相同的， kinit时会自动同步回来的。&lt;br&gt;&#10;公司的大数据平台使用&lt;a class="link" href="http://gethue.com/" target="_blank" rel="noopener"&#10; &gt;Hue&lt;/a&gt;来提供基于web界面的查询，Impala也支持使用ODBC方式查询。在Python里使用的是&lt;a class="link" href="https://github.com/cloudera/impyla" target="_blank" rel="noopener"&#10; &gt;impyla&lt;/a&gt;来查询，首先安装sasl的依赖&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install libgsasl-devel cyrus-sasl-devel cyrus-sasl-gssapi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install impyla thrift_sasl&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试脚本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; impala.dbapi &lt;span style="color:#f92672"&gt;import&lt;/span&gt; connect&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; connect(host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;impalad.example.com&amp;#34;&lt;/span&gt;, port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;21050&lt;/span&gt;, auth_mechanism&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;GSSAPI&amp;#39;&lt;/span&gt;, kerberos_service_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;impala&amp;#39;&lt;/span&gt;, database&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;acme&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cur &lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cursor()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cur&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;SELECT * FROM acme WHERE dt=&amp;#34;2017-09-12&amp;#34; LIMIT 5&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(cur&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fetchall())&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python test.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如下报错，则是服务器不能连接，检查一下网络，DNS/hosts及VPN&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thriftpy.transport.TTransportException: TTransportException&lt;span style="color:#f92672"&gt;(&lt;/span&gt;type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1, message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Could not connect to (&amp;#39;impalad.example.com&amp;#39;, 21050)&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如下报错，CentOS则是需要cyrus-sasl-gssapi模块&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thriftpy.transport.TTransportException: TTransportException&lt;span style="color:#f92672"&gt;(&lt;/span&gt;type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1, message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Could not start SASL: b&amp;#39;Error in sasl_client_start (-4) SASL(-4): no mechanism available: No worthy mechs found&amp;#39;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.parallellabs.com/2013/08/25/impala-big-data-analytics/" target="_blank" rel="noopener"&#10; &gt;Impala：新一代开源大数据分析引擎&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ywnds.com/?p=9404" target="_blank" rel="noopener"&#10; &gt;大数据时代快速SQL引擎-Impala&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000002532307" target="_blank" rel="noopener"&#10; &gt;CDH 5.2中Impala认证集成LDAP和Kerberos&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://help.ubuntu.com/community/Kerberos" target="_blank" rel="noopener"&#10; &gt;Kerberos&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.simba.com/products/Impala/doc/JDBC_InstallGuide/content/jdbc/hi/kerberos.htm" target="_blank" rel="noopener"&#10; &gt;Configuring Kerberos Authentication for Windows&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.knime.com/blog/speaking-kerberos-with-knime-big-data-extensions" target="_blank" rel="noopener"&#10; &gt;Speaking Kerberos with KNIME Big Data Extensions&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用Supervisor 管理监控进程</title><link>https://courages.us/%E4%BD%BF%E7%94%A8superviosr-%E7%AE%A1%E7%90%86%E7%9B%91%E6%8E%A7%E8%BF%9B%E7%A8%8B/</link><pubDate>Sat, 30 Sep 2017 09:38:29 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8superviosr-%E7%AE%A1%E7%90%86%E7%9B%91%E6%8E%A7%E8%BF%9B%E7%A8%8B/</guid><description>&lt;p&gt;&lt;a class="link" href="http://supervisord.org/introduction.html" target="_blank" rel="noopener"&#10; &gt;Supervisor&lt;/a&gt;是用Python写的一款应用程监控管理工具，能够启动，停止，重启死进程，提供web管理界面，XML-RPC接口及事件监听。通常我们写了一些脚本都不会带有daemon功能，而是加&amp;amp;或者nohub，screen什么的丢到后台去运行，同时使用corntab定时检测脚本是否存活，以便重新运行脚本。使用Supervisor可以将这些脚本，程序转为守护进程，自动重启它们；还可以监控机器的进程运行状况，输出警报等。&lt;br&gt;&#10;Supervisor只能运行于Python 2.x的环境，但子进程可以为其他任意程序，比如Python 3，PHP等。这里使用pip来安装&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ wget https://bootstrap.pypa.io/get-pip.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo python get-pip.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo pip install supervisor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成配置文件及日志目录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo echo_supervisord_conf &amp;gt; /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mkdir /var/log/supervisor&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chmod &lt;span style="color:#ae81ff"&gt;655&lt;/span&gt; /var/log/supervisor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动supervisord&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo supervisord -c /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisorctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ Server requires authentication&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ Username:user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisor&amp;gt; status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisor&amp;gt; help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;default commands &lt;span style="color:#f92672"&gt;(&lt;/span&gt;type help &amp;lt;topic&amp;gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;=====================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add exit open reload restart start tail&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;avail fg pid remove shutdown status update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clear maintail quit reread signal stop version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisor&amp;gt; quit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里没有任何进程。以下为常用命令：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;supervisorctl stop program 停止某个进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl start program 启动某个进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl restart program 重启某个进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl stop group 重启属于group分组的所有进程(start,restart同理)&lt;/li&gt;&#10;&lt;li&gt;supervisorctl stop all 停止全部进程，注：start、restart、stop都不会载入最新的配置文件&lt;/li&gt;&#10;&lt;li&gt;supervisorctl reload 载入最新配置文件，停止原有进程并按新配置启动进程&lt;/li&gt;&#10;&lt;li&gt;supervisorctl update 根据最新配置文件，启动新配置或有改动的进程，没有改动的进程不受影响&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;编辑supervisord.conf启用web界面，账号密码为web及supervisorctl共用，必须更改&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#取消以下行的注释&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;inet_http_server&lt;span style="color:#f92672"&gt;]&lt;/span&gt; ; inet &lt;span style="color:#f92672"&gt;(&lt;/span&gt;TCP&lt;span style="color:#f92672"&gt;)&lt;/span&gt; server disabled by default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;*:9002 ; ip_address:port specifier, *:port &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; all iface&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;username&lt;span style="color:#f92672"&gt;=&lt;/span&gt;user ; default is no username &lt;span style="color:#f92672"&gt;(&lt;/span&gt;open server&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;password&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;123&lt;/span&gt; ; default is no password &lt;span style="color:#f92672"&gt;(&lt;/span&gt;open server&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#添加新应用qrd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;program:qrd&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;directory &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autostart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autorestart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startsecs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startretries &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stdout_logfile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /var/log/supervisor/qrd.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stderr_logfile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; /var/log/supervisor/qrd.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启使HTTP配置生效&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps aux | grep supervisord &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisord -c /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于supervisord.conf配置项，命令释义可以参考&lt;a class="link" href="http://zhangweide.cn/archive/2013/supervisor-note.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;command 为要运行的脚本或程序&lt;/li&gt;&#10;&lt;li&gt;directory 为脚本或程序运行时的工作目录&lt;/li&gt;&#10;&lt;li&gt;user 为脚本或程序运行时的用户&lt;/li&gt;&#10;&lt;li&gt;autostart 随supervisord启动&lt;/li&gt;&#10;&lt;li&gt;startsecs 启动后等待时间，过了这个时间没起来就重新启动&lt;/li&gt;&#10;&lt;li&gt;startretries 启动失败后重试的次数&lt;/li&gt;&#10;&lt;li&gt;stdout_logfile，stderr_logfile 为输出日志&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;重新加载所有应用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ supervisorctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Server requires authentication&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Username:user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Password:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Really restart the remote supervisord process y/N? y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Restarted supervisord&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrd RUNNING pid 3861, uptime 0:00:22&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到定义的qrd程序已经起来了。如果qrd程序意外退出了，那么supervisord将会重启它。如果杀掉了supervisord，那么qrd对应的进程也将被杀死。也可以去web界面查看http://127.0.0.1:9002/&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2017/09/supervisor04.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="705px" data-flex-grow="294" height="102" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2017/09/supervisor04-300x102.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;可以通过web页面来启动，停止进程，查看日志等。&lt;br&gt;&#10;再增加下&lt;a class="link" href="https://github.com/celery/celery/tree/master/extra/supervisord" target="_blank" rel="noopener"&#10; &gt;Celery的Worker，Beat配置&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;==================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; celery worker supervisor example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;==================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;program:qrdworker&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set full path to celery program &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; using virtualenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/celery worker -A qrd --loglevel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;INFO&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Alternatively,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;celery --app&lt;span style="color:#f92672"&gt;=&lt;/span&gt;your_app.celery:app worker --loglevel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;INFO -n worker.%%h&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Or run a script&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;celery.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;directory&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;numprocs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stdout_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/qrdworker.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stderr_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/qrdworker.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autostart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autorestart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startsecs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Need to wait &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; currently executing tasks to finish at shutdown.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Increase this &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you have very long running tasks.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stopwaitsecs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Causes supervisor to send the termination signal &lt;span style="color:#f92672"&gt;(&lt;/span&gt;SIGTERM&lt;span style="color:#f92672"&gt;)&lt;/span&gt; to the whole process group.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stopasgroup&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set Celery priority higher than default &lt;span style="color:#f92672"&gt;(&lt;/span&gt;999&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; so, &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; rabbitmq is supervised, it will start first.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;priority&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; celery beat supervisor example&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#f92672"&gt;================================&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;program:qrdbeat&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set full path to celery program &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; using virtualenv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/celery -A qrd beat -l info -s /tmp/celerybeat-schedule&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; remove the -A myapp argument &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; you aren&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t using an app instance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;directory&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/qrd/qrd/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nobody&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;numprocs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stdout_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/beat.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stderr_logfile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/log/supervisor/beat.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autostart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;autorestart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;startsecs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Causes supervisor to send the termination signal &lt;span style="color:#f92672"&gt;(&lt;/span&gt;SIGTERM&lt;span style="color:#f92672"&gt;)&lt;/span&gt; to the whole process group.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stopasgroup&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; rabbitmq is supervised, set its priority higher&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; so it starts first&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;priority&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;999&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启用它们&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrdbeat: added process group&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;supervisor&amp;gt; status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrd RUNNING pid 4468, uptime 0:03:49&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrdbeat BACKOFF Exited too quickly &lt;span style="color:#f92672"&gt;(&lt;/span&gt;process log may have details&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qrdworker RUNNING pid 4469, uptime 0:03:49&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看下进程&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo ps aux | grep python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;1038&lt;/span&gt; 0.0 3.1 &lt;span style="color:#ae81ff"&gt;562392&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15720&lt;/span&gt; ? Ssl 01:49 0:01 /usr/bin/python -Es /usr/sbin/tuned -l -P&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3992&lt;/span&gt; 0.1 3.0 &lt;span style="color:#ae81ff"&gt;222124&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15224&lt;/span&gt; ? Ss 03:49 0:00 /bin/python /bin/supervisord -c /etc/supervisord.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3993&lt;/span&gt; 0.3 3.8 &lt;span style="color:#ae81ff"&gt;211868&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19296&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3996&lt;/span&gt; 0.3 6.9 &lt;span style="color:#ae81ff"&gt;264048&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34780&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3998&lt;/span&gt; 0.3 6.9 &lt;span style="color:#ae81ff"&gt;264056&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34784&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;3999&lt;/span&gt; 0.4 6.9 &lt;span style="color:#ae81ff"&gt;264024&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34784&lt;/span&gt; ? S 03:49 0:00 /usr/local/python3/bin/python3.6 /usr/bin/gunicorn --access-logfile - --workers &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --bind 127.0.0.1:8000 qrd.wsgi&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;4014&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;112660&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;976&lt;/span&gt; pts/0 R+ 03:50 0:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除了program标签，Supervisor也支持group标签，用来启动一系列的program，比如先启动数据库，再启动web服务器。&lt;br&gt;&#10;Supervisor也可以用来管理PHP进程，比如&lt;a class="link" href="https://blog.tanteng.me/2017/01/supervisor-laravel-queue/" target="_blank" rel="noopener"&#10; &gt;使用 Supervisor 管理 Laravel 队列进程&lt;/a&gt;。&lt;br&gt;&#10;Docker官方推荐一个docker容器只运行一个服务，如果你想启动多个脚本或程序，可以&lt;a class="link" href="https://docs.docker.com/engine/admin/multi-service_container/" target="_blank" rel="noopener"&#10; &gt;使用Supervisor会更简单点&lt;/a&gt;。&lt;br&gt;&#10;如果需要Supervisor开启启动，可以使用&lt;a class="link" href="https://github.com/Supervisor/initscripts" target="_blank" rel="noopener"&#10; &gt;GitHub上的脚本和配置&lt;/a&gt;。CentOS 7上可以配置为service，由systemctl来管理：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/systemd/system/supervisord.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内容如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# supervisord service for systemd (CentOS 7.0+)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# by ET-CS (https://github.com/ET-CS)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Unit&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Supervisor daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Service&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;forking&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/supervisord&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStop&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/supervisorctl $OPTIONS shutdown&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecReload&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/bin/supervisorctl $OPTIONS reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KillMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Restart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;on-failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RestartSec&lt;span style="color:#f92672"&gt;=&lt;/span&gt;42s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;Install&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WantedBy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo systemctl enable supervisord.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Created symlink from /etc/systemd/system/multi-user.target.wants/supervisord.service to /etc/systemd/system/supervisord.service.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo systemctl start supervisord.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo ps aux | grep python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然supervisorctl及web界面都只能管理本机，但是Supervisor提供了&lt;a class="link" href="http://supervisord.org/api.html" target="_blank" rel="noopener"&#10; &gt;XML-RPC接口&lt;/a&gt;，可以获取进程运行信息，因此诞生了许多&lt;a class="link" href="http://supervisord.org/plugins.html" target="_blank" rel="noopener"&#10; &gt;监控平台&lt;/a&gt;，以便监控服务器集群的进程的运行状况。&lt;br&gt;&#10;Supervisor还提供了&lt;a class="link" href="http://supervisord.org/events.html" target="_blank" rel="noopener"&#10; &gt;event listener配置&lt;/a&gt;，在这里Supervisor将会通知脚本其他进程的运行状态变更的事件，可以用来发送警报监控等。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://idoall.org/blog/post/lion/10" target="_blank" rel="noopener"&#10; &gt;使用Supervisor3.2.1基于Mac10.10.3对系统进程进行管理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.jianshu.com/p/eeeedc69b560" target="_blank" rel="noopener"&#10; &gt;supervisor的配置浅析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.restran.net/2015/10/04/supervisord-tutorial/" target="_blank" rel="noopener"&#10; &gt;Python 进程管理工具 Supervisor 使用教程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.do1618.com/archives/342" target="_blank" rel="noopener"&#10; &gt;Supervisor进程监护使用指南&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000000606682" target="_blank" rel="noopener"&#10; &gt;supervisord 的 XML-RPC API 使用说明&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://chenjiehua.me/linux/supervisor-event-listenser.html" target="_blank" rel="noopener"&#10; &gt;Supervisor Event Listener&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.tothenew.com/blog/dockerizing-nginx-and-ssh-using-supervisord/" target="_blank" rel="noopener"&#10; &gt;Dockerizing Nginx and SSH using Supervisord&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP MongoDB Replica Set应用</title><link>https://courages.us/php-mongodb-replica-set%E5%BA%94%E7%94%A8/</link><pubDate>Sat, 23 Sep 2017 16:10:53 +0800</pubDate><guid>https://courages.us/php-mongodb-replica-set%E5%BA%94%E7%94%A8/</guid><description>&lt;p&gt;&lt;a class="link" href="https://www.mongodb.com/" target="_blank" rel="noopener"&#10; &gt;MongoDB&lt;/a&gt;是个面向文档管理的NoSQL数据库，能够直接存取JSON数据，支持海量数据。公司内部的一个单点登录系统使用MongoDB来存储用户的session，以便在不同应用，服务器之间共享登录信息，解决了服务器切换用户状态丢失（被登出）的问题。单点登录系统前端采用PHP，与&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E8%BD%BB%E5%9E%8B%E7%9B%AE%E5%BD%95%E8%AE%BF%E9%97%AE%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;LDAP&lt;/a&gt;交互认证用户信息，提供登录界面，API等。MongoDB则采用Replica Set模式以便支持高可用。&lt;br&gt;&#10;在CentOS 6.5上安装MongoDB，首先添加源仓库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ suod vim /etc/yum.repos.d/mongodb.repo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;mongodb&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;MongoDB Repository&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;baseurl&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpgcheck&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装，启动，连接MongoDB&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo yum --enablerepo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mongodb install mongodb-org&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /sbin/chkconfig --levels &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; mongod on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo mongod --port &lt;span style="color:#ae81ff"&gt;27017&lt;/span&gt; --dbpath /data/db1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mongo --port &lt;span style="color:#ae81ff"&gt;27017&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建用户SSOReplUser&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; db.createUser&lt;span style="color:#f92672"&gt;(&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; user: &lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, pwd: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;, roles: &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; role: &lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;, db: &lt;span style="color:#e6db74"&gt;&amp;#34;admin&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;})&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建集群要用到的key&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo openssl rand -base64 &lt;span style="color:#ae81ff"&gt;741&lt;/span&gt; &amp;gt; /home/sso/mongodb-keyfile &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo chmod &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt; /home/sso/mongodb-keyfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑MongoDB配置文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vim /etc/mongod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Replication Options &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# in replicated mongo databases, specify the replica set name here &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;replSet&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SSOReplSet &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# maximum size in megabytes for replication operation log &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#oplogSize=1024 &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# path to a key file storing authentication info for connections # between replica set members keyFile=/home/sso/mongodb-keyfile&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启mongod服务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /etc/init.d/mongod stop &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /usr/bin/mongod -f /etc/mongod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用SSOReplUser登录&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; db.auth&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;初始化集群&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; rs.initiate&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; rs.conf&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplSet&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: 1,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;members&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;: 1,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;host&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.10:27017&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在其他机器上按照上面步骤安装MongoDB，更改配置，复制对应的mongodb-keyfile并启动。&lt;br&gt;&#10;回到192.168.33.10并添加机器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.11:27017&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.12:27017&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.add&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.13:27017&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SSOReplSet:PRIMARY&amp;gt; rs.remove(&amp;#34;192.168.33.13:27017&amp;#34;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在从机上认证查看&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:SECONDARY&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:SECONDARY&amp;gt; db.auth&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:SECONDARY&amp;gt; rs.status&lt;span style="color:#f92672"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MongoDB的Replica set模式最少要求3台机器，以便在PRIMARY机器故障时，能够自我选举出新的PRIMARY,但需要n/2+1的机器投票同意。例如刚才配置了4台机器，那么需要4/2+1=3台机器投票，能够承受一台机器故障。如果是集群有5台机器，则能够承受2台机器故障。因此再配置一台不存储数据的&lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/add-replica-set-arbiter/" target="_blank" rel="noopener"&#10; &gt;Arbiter机器&lt;/a&gt;比较合理。&lt;br&gt;&#10;按照上面的步骤安装，复制mongodb-keyfile文件，但需要更改mongod.conf&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo vim /etc/mongod.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nojournal&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启动mongod服务并在PRIMARY机器上将这台机器加入机器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; use admin &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; db.auth&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;SSOReplUser&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;password&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SSOReplSet:PRIMARY&amp;gt; rs.addArb&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;ip of arbiter&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP的mongo扩展安装比较简单，下载对应版本，启用即可。然而在应用过程中发现登录有点慢，启用看PHP mongo扩展&lt;a class="link" href="http://php.net/manual/en/mongodb.setprofilinglevel.php" target="_blank" rel="noopener"&#10; &gt;profiling功能&lt;/a&gt;，查看PHP日志&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setLevel&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setModule&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\MongoLog&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aaa01(primary)&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\MongoClient&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mongodb://admin:XXXXXXXXX@192.168.33.10:27017/?replicaSet=SSOReplSet &amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aaa01(primay), bbb01(secondary),ccc01(secondary),ddd01(secondary)&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\MongoClient&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mongodb://admin:XXXXXXXXX@192.168.33.10:27017,192.168.33.11:27017,192.168.33.12:27017,192.168.33.13:27017/?replicaSet=SSOReplSet &amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;\MongoConnectionException&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($e);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现PHP连接MongoDB集群是这样子的&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2017/09/%e6%97%a7%e5%90%8e%e5%8f%b0.png" target="_blank" rel="noopener"&#10; &gt;&lt;img class="gallery-image" data-flex-basis="300px" data-flex-grow="125" height="240" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2017/09/旧后台-300x240.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;即：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1）在连接里面配置了几个MongoDB连接服务器，PHP每个都会创建连接去查询&lt;/li&gt;&#10;&lt;li&gt;2）从每台服务器上查询出整个集群的服务器列表，再分别ping和连接这些服务器，如果连接不存在或不匹配则创建，无效的则销毁&lt;/li&gt;&#10;&lt;li&gt;3）汇总所有服务器返回集群列表&lt;/li&gt;&#10;&lt;li&gt;4）选择离自己最近的服务器并使用该与该服务器的连接&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;MongoDB 的写操作默认在Primary节点上操作完成即返回成功；读操作默认是也是从Primary上读取，所以需要去查询服务器。由于SSO应用部署在多个数据中心，网络抖动会造成较大影响，跨数据中心的查询并不会很快，如果每次都去连接并查询整个列表是比较耗时。另外如果在php里面配置的是IP而MongoDB Replica Set里面配置的是域名，则连接名会出现不匹配，而创建新的连接并销毁旧连接，也耗时。如果配置的是域名，则需要DNS解析。由于每台PHP服务器均已配置HA检测，最终每个应用只配置了一台服务器，并统一配置MongoDB集群为IP。而连接最快的是在Primary机器上，可以根据本机是否Primary来做HA：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/env bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;ps -fe |grep &lt;span style="color:#e6db74"&gt;&amp;#34;mongod&amp;#34;&lt;/span&gt; | grep -v &lt;span style="color:#e6db74"&gt;&amp;#34;grep&amp;#34;&lt;/span&gt; | wc -l&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FILE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/home/scripts-bits/master.conf&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SERVER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;hostname&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; $count -lt &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rm -f $FILE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PRIMAY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;/usr/bin/mongo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;SERVER&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:27017 --quiet --eval &lt;span style="color:#e6db74"&gt;&amp;#39;printjson(db.isMaster().ismaster);&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$PRIMAY&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; ! -f &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$FILE&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&#9;touch &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$FILE&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;REMOVE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;/usr/bin/mongo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;SERVER&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:27017/admin --quiet /home/scripts-bits/mongo_status.js&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;删除故障节点(not reachable/healthy)的脚本mongo_status.js:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;auth&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;password&amp;gt;&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;conf&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;status&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;conf&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;members&amp;#34;&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#34;state&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;rs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;remove&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;members&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这中间也出现过因为网络/机器故障，导致PHP等待连接超时的情况的，将该机器从集群中移除即可。然而当服务器是启动的（可以到达）情况下，MongoDB故障，则不会超时。可以更改connectTimeoutMS，以便减少等待。&lt;br&gt;&#10;MongoDB的日志默认都是记录在/var/log/mongodb/下面并且会越来越大。创建Python脚本来定时清除它：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/env python&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; commands&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;,&lt;/span&gt;time&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rotate_log&lt;/span&gt;(path, expire &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; str_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dat_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strptime(str_now, &lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; array_dat_now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime(dat_now[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], dat_now[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], dat_now[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;])&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lns &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(&lt;span style="color:#e6db74"&gt;&amp;#34;/bin/ls --full-time &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;|awk &amp;#39;{print $6, $9}&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; path)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ln &lt;span style="color:#f92672"&gt;in&lt;/span&gt; lns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ws &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ln&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; len(ws) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ws1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strptime(ws[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ws2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime(ws1[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], ws1[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], ws1[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;])&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (array_dat_now &lt;span style="color:#f92672"&gt;-&lt;/span&gt; ws2)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;days &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; expire:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v_del &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(&lt;span style="color:#e6db74"&gt;&amp;#34;/bin/rm -rf &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (path, ws[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rotate_mongo&lt;/span&gt;():&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# get mongo pid&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mongo_pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(&lt;span style="color:#e6db74"&gt;&amp;#34;/sbin/pidof mongod&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#print mongo_pid&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# send Sig to mongo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; mongo_pid &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/kill -USR1 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (mongo_pid)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# print cmd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mongo_rotate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; commands&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getoutput(cmd)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print &lt;span style="color:#e6db74"&gt;&amp;#34;mongod is not running...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/var/log/mongodb/&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; expire &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rotate_mongo()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rotate_log(log_path, expire)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加入到crontab里面去执行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; * * * /usr/bin/python /home/sso/mongo_rotate.py &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考连接&lt;br&gt;&#10;&lt;a class="link" href="http://www.jianshu.com/p/7a41907a1549" target="_blank" rel="noopener"&#10; &gt;mongodb与mysql相比的优缺点&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/mongo.connecting.rs.php" target="_blank" rel="noopener"&#10; &gt;PHP MongoDB 复制集合&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/replication/" target="_blank" rel="noopener"&#10; &gt;MongoDB Replication&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/enable-authentication/" target="_blank" rel="noopener"&#10; &gt;MongoDB Enable Auth&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/rotate-log-files/" target="_blank" rel="noopener"&#10; &gt;MongoDB Rotate Log Files&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://jira.mongodb.org/browse/PHPC-723" target="_blank" rel="noopener"&#10; &gt;Blocking connect() leads to cumulative timeouts for multiple inaccessible servers&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.slideshare.net/profyclub_ru/3-how-raft-consensus-algorithm-will-make-replication-even-better-in-mongo-db-32-henrik-ingo-mongodb" target="_blank" rel="noopener"&#10; &gt;How Raft consensus algorithm will make replication even better in MongoDB 3.2&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/core/replica-set-write-concern/" target="_blank" rel="noopener"&#10; &gt;Write Concern for Replica Sets&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.mongodb.com/manual/core/read-preference/" target="_blank" rel="noopener"&#10; &gt;MongoDB Read Preference&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Vagrant CentOS 共享目录挂载问题解决</title><link>https://courages.us/vagrant-centos-%E5%85%B1%E4%BA%AB%E7%9B%AE%E5%BD%95%E6%8C%82%E8%BD%BD%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/</link><pubDate>Sun, 17 Sep 2017 10:07:01 +0800</pubDate><guid>https://courages.us/vagrant-centos-%E5%85%B1%E4%BA%AB%E7%9B%AE%E5%BD%95%E6%8C%82%E8%BD%BD%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/</guid><description>&lt;p&gt;一直以来都是使用Vagrant与VirtualBox运行CentOS系统来搭建环境，然而有一天突然出现Windows下面的目录无法映射进去了，报错:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;D:&lt;span style="color:#ae81ff"&gt;\p&lt;/span&gt;roject&lt;span style="color:#ae81ff"&gt;\v&lt;/span&gt;agrant&lt;span style="color:#ae81ff"&gt;\c&lt;/span&gt;entos64php56&amp;gt;vagrant up&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Bringing machine &lt;span style="color:#e6db74"&gt;&amp;#39;default&amp;#39;&lt;/span&gt; up with &lt;span style="color:#e6db74"&gt;&amp;#39;virtualbox&amp;#39;&lt;/span&gt; provider...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Clearing any previously set forwarded ports...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Clearing any previously set network interfaces...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Preparing network interfaces based on configuration...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Adapter 1: nat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Adapter 2: hostonly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Forwarding ports...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;guest&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;host&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;adapter 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;guest&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; &lt;span style="color:#ae81ff"&gt;2222&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;host&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;adapter 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Booting VM...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Waiting &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; machine to boot. This may take a few minutes...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH address: 127.0.0.1:2222&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH username: vagrant&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH auth method: private key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Connection reset. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Connection aborted. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Connection reset. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Warning: Remote connection disconnect. Retrying...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Machine booted and ready!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;default&lt;span style="color:#f92672"&gt;]&lt;/span&gt; GuestAdditions versions on your host &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5.1.26&lt;span style="color:#f92672"&gt;)&lt;/span&gt; and guest &lt;span style="color:#f92672"&gt;(&lt;/span&gt;4.3.6&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; not matc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loaded plugins: fastestmirror&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Setting up Install Process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Loading mirror speeds from cached hostfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * base: mirrors.btte.net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * epel: repo.fedoralinux.ir&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * extras: mirrors.btte.net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; * updates: mirrors.btte.net&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No package kernel-devel-2.6.32-358.23.2.el6.x86_64 available.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package gcc-4.4.7-18.el6.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package binutils-2.20.51.0.2-5.47.el6_9.1.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package 1:make-3.81-23.el6.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package 4:perl-5.10.1-144.el6.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Package bzip2-1.0.5-7.el6_0.x86_64 already installed and latest version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Nothing to &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copy iso file C:&lt;span style="color:#ae81ff"&gt;\P&lt;/span&gt;rogram Files&lt;span style="color:#ae81ff"&gt;\O&lt;/span&gt;racle&lt;span style="color:#ae81ff"&gt;\V&lt;/span&gt;irtualBox&lt;span style="color:#ae81ff"&gt;\V&lt;/span&gt;BoxGuestAdditions.iso into the box&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing Virtualbox Guest Additions 5.1.26 - guest version is 4.3.6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Verifying archive integrity... All good.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Uncompressing VirtualBox 5.1.26 Guest Additions &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Linux...........&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VirtualBox Guest Additions installer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Removing installed version 5.1.26 of VirtualBox Guest Additions...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Stopping VirtualBox Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Copying additional installer modules ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Installing additional modules ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Failed to set up service vboxadd, please check the log file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/var/log/VBoxGuestAdditions.log &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; details.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;An error occurred during installation of VirtualBox Guest Additions 5.1.26. Some func&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;In most cases it is OK that the &lt;span style="color:#e6db74"&gt;&amp;#34;Window System drivers&amp;#34;&lt;/span&gt; installation failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: Look at /var/log/vboxadd-install.log to find out what went wrong.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: modprobe vboxguest failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Checking &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; guest additions in VM...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: The guest additions on this VM &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; not match the installed version of&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: VirtualBox! In most cases this is fine, but in rare cases it can&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: prevent things such as shared folders from working properly. If you see&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: shared folder errors, please make sure the guest additions within the&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: virtual machine match the version of VirtualBox you have installed on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: your host and reload your VM.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: Guest Additions Version: 4.3.6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: VirtualBox Version: 5.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Configuring and enabling network interfaces...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH address: 127.0.0.1:2222&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH username: vagrant&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: SSH auth method: private key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; default: Mounting shared folders...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default: /home/rc &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; D:/project/vagrant/centos64php56&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Vagrant was unable to mount VirtualBox shared folders. This is usually&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;because the filesystem &lt;span style="color:#e6db74"&gt;&amp;#34;vboxsf&amp;#34;&lt;/span&gt; is not available. This filesystem is&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;made available via the VirtualBox Guest Additions and kernel module.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Please verify that these guest additions are properly installed in the&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;guest. This is not a bug in Vagrant and is usually caused by a faulty&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Vagrant box. For context, the command attempted was:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mount -t vboxsf -o uid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;500,gid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; home_rc_ /home/rc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;The error output from the command was:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/sbin/mount.vboxsf: mounting failed with the error: No such device&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里提示虚拟机里CentOS的VBoxGuestAdditions与VirtualBox的版本匹配，需要升级：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;default&lt;span style="color:#f92672"&gt;]&lt;/span&gt; GuestAdditions versions on your host &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5.1.26&lt;span style="color:#f92672"&gt;)&lt;/span&gt; and guest &lt;span style="color:#f92672"&gt;(&lt;/span&gt;4.3.6&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; not matc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应该是升级了VirtualBox导致的。然而自动安装新插件失败:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Failed to set up service vboxadd, please check the log file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/var/log/VBoxGuestAdditions.log &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; details.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;An error occurred during installation of VirtualBox Guest Additions 5.1.26. Some func&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;In most cases it is OK that the &lt;span style="color:#e6db74"&gt;&amp;#34;Window System drivers&amp;#34;&lt;/span&gt; installation failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: Starting the VirtualBox Guest Additions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: Look at /var/log/vboxadd-install.log to find out what went wrong.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vboxadd.sh: failed: modprobe vboxguest failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;导致共享目录无法映射。但是虚拟机仍然是启动成功的，可以ssh进去，或者使用sftp挂载。&lt;br&gt;&#10;Google了下有说是&lt;a class="link" href="https://gist.github.com/fernandoaleman/5083680" target="_blank" rel="noopener"&#10; &gt;VirtualBox bug&lt;/a&gt;的，也有说是Windows问题的，各种折腾不能解决。升级插件也无效：vagrant plugin install vagrant-vbguest。重新安装VirtualBox和Vagrant，并不会影响现有虚拟机及网络配置，但不能解决问题。&lt;br&gt;&#10;直到看到&lt;a class="link" href="https://urouge.me/share-folder-mount-error-in-virtualbox/" target="_blank" rel="noopener"&#10; &gt;这篇文章&lt;/a&gt;，决定从CentOS入手解决。&lt;br&gt;&#10;启动虚拟机后，使用sftp上传VBoxGuestAdditions.iso，ssh进入手动安装：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mount VBoxGuestAdditions.iso -o loop /mnt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd /mnt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sh VBoxLinuxAdditions.run&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装失败，查看日志：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Building the main Guest Additions module &lt;span style="color:#f92672"&gt;[&lt;/span&gt;FAILED&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;Look at /var/log/vboxadd-install.log to find out what went wrong&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;vboxadd-install.log日志：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/tmp/vbox.0/Makefile.include.header:97: *** Error: unable to find the sources of your current Linux kernel. Specify KERN_DIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;lt;directory&amp;gt; and run Make again. Stop.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参照&lt;a class="link" href="https://www.centos.org/forums/viewtopic.php?t=45163" target="_blank" rel="noopener"&#10; &gt;这篇文章&lt;/a&gt;，查看kernel版本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ rpm -qa kernel&lt;span style="color:#ae81ff"&gt;\*&lt;/span&gt; | sort&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-2.6.32-358.23.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-devel-2.6.32-696.10.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-firmware-2.6.32-358.10.2.el6.noarch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kernel-headers-2.6.32-696.10.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ uname -r&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2.6.32-358.10.2.el6.x86_64&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实一开始是更多版本不匹配的，尝试更新kernel:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install kernel-headers kernel-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果部分更新失败：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Warning: No matches found &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;: kernel-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No Matches found&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参照&lt;a class="link" href="https://stackoverflow.com/questions/29396322/warning-no-matches-found-for-kernel-devel" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;解除版本锁定，设置enabled = 0：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ vim /etc/yum/pluginconf.d/versionlock.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次运行升级kernel就可以了。安装成功后，重启后，再次运行sh VBoxLinuxAdditions.run 就可以了。事实上Vagrant启动时就会自动安装VBoxGuestAdditions：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;default&lt;span style="color:#f92672"&gt;]&lt;/span&gt; GuestAdditions 5.1.26 running --- OK.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Vagrant升级到后发现vagrant up初始化下载box卡住了，那是你的vagrant版本太高与对应的powershell版本对应不上，可以下载最新的powershell安装即可。&lt;br&gt;&#10;如果box下载很慢，可以参照&lt;a class="link" href="https://urouge.me/how-to-download-vagrant-boxes/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;的方法自我映射取得url单独下载：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://app.vagrantup.com/box-cutter/boxes/centos73&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&amp;gt; https://atlas.hashicorp.com/box-cutter/boxes/centos73/versions/2.0.21/providers/virtualbox.box&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/Varying-Vagrant-Vagrants/VVV/issues/714" target="_blank" rel="noopener"&#10; &gt;Guest Additions Version error on VirtualBox5&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://urouge.me/share-folder-mount-error-in-virtualbox/" target="_blank" rel="noopener"&#10; &gt;VirtualBox下挂载共享文件目录问题处理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://codingbeauty.wordpress.com/2015/10/13/resolving-guestadditions-version-mismatch-in-vagranthomestead-vm-failed-to-mount-shared-folders-modprobe-vboxsf-failed/" target="_blank" rel="noopener"&#10; &gt;Resolving GuestAdditions version mismatch in vagrant/homestead vm (failed to mount shared folders / modprobe vboxsf failed)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.centos.org/forums/viewtopic.php?t=45163" target="_blank" rel="noopener"&#10; &gt;Problem installing virtualBox guest additions&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://stackoverflow.com/questions/29396322/warning-no-matches-found-for-kernel-devel" target="_blank" rel="noopener"&#10; &gt;Warning: No matches found for: kernel-devel&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/hashicorp/vagrant/issues/8777" target="_blank" rel="noopener"&#10; &gt;Vagrant up hangs forever on Windows 7, Vagrant 1.9.7, VirtualBox 5.1.22.r11512&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>TCP UDP探索</title><link>https://courages.us/tcp-udp%E6%8E%A2%E7%B4%A2/</link><pubDate>Sat, 03 Dec 2016 16:19:12 +0800</pubDate><guid>https://courages.us/tcp-udp%E6%8E%A2%E7%B4%A2/</guid><description>&lt;p&gt;最近开发新接口，为实现更高的性能，深入考察了下TCP，UDP通信协议。之前的开发当中都是基于HTTP的接口开发，简单易用，各个编程语言都支持；web服务器、中间件成熟，方便扩展；支持安全加密等等。与自定义Socket通信相比，HTTP仍然不够高效。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;TCP协议&lt;/a&gt;，也叫传输控制协议（Transmission Control Protocol）是一种面向连接的、可靠的、基于字节流的传输层通信协议。每建立一个TCP连接需要三次握手，关闭时又需要四次握手；传输过程当中，每发送一个包，都要接收一个确认回复，如果在一定时间内未收到，则重发，如果是同一块数据分包传输，则回复所需要的包序号；在发送和接收时都要计算校验和。由于有严格的数据包传输顺序和校验，因为接收到的数据将会是顺序。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E7%94%A8%E6%88%B7%E6%95%B0%E6%8D%AE%E6%8A%A5%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;UDP协议&lt;/a&gt;，也叫用户数据报协议（User Datagram Protocol）是一个简单的面向数据报的传输层协议。它只管数据包发送，并不没有TCP的连接控制、回复确认，并不知道对方是否接收成功。因为并不等待接收方回复，发送端可以连续发送数据，接收端接收到数据并不一定是顺序的。因此相比TCP，UDP的有更高的传输效率，更低的可靠性。如果需要可靠性，则需要发送确认包，类似TCP那样子。&lt;/p&gt;&#10;&lt;p&gt;通常&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE" target="_blank" rel="noopener"&#10; &gt;HTTP协议&lt;/a&gt;基于TCP实现，保证收到的内容是完整、顺序的。在HTTP 1.0时，每一次请求都需要建立TCP连接，关闭TCP连接；在HTTP 1.1时，同一TCP连接则可以在活跃（Keep-Live）间期内复用。HTTP是无连接的，每次处理完成请求即断开连接，一方面可以节省服务器资源，另一方面却浪费连接时间。如果需要维持客户端的Keep-Alive状态，则又需要消耗更多服务器资源，需要权衡。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/WebSocket" target="_blank" rel="noopener"&#10; &gt;WebSocket&lt;/a&gt;是基于TCP 连接上进行全双工通讯的协议，允许服务端直接向浏览器发送消息，不再需要ajax轮询。它也是&lt;a class="link" href="http://stackoverflow.com/questions/35315641/can-tcp-udp-sockets-and-websockets-communicate-with-each-other" target="_blank" rel="noopener"&#10; &gt;在TCP上面的实现&lt;/a&gt;，使用类似HTTP请求的握手协议，进行TCP通信切换。&lt;a class="link" href="https://zh.wikipedia.org/wiki/WebRTC" target="_blank" rel="noopener"&#10; &gt;WebRTC&lt;/a&gt;，也叫Web即时通信（Web Real-Time Communication），则是一个支持浏览器之间进行实时语音对话或视频对话的API。它是建立于TCP/UDP之上的点对点通信，客户端基于上层&lt;a class="link" href="https://www.html5rocks.com/en/tutorials/webrtc/datachannels/" target="_blank" rel="noopener"&#10; &gt;RTCDataChannel&lt;/a&gt;进行通信而非底层TCP/UDP。&lt;/p&gt;&#10;&lt;p&gt;Google推出了基于UDP的&lt;a class="link" href="https://zh.wikipedia.org/wiki/QUIC" target="_blank" rel="noopener"&#10; &gt;QUIC协议（快速UDP网络连接）&lt;/a&gt;实现的HTTP传输，可以快速在两个端点间创建连接，支持多路复用连接。对于丢包问题，则采用冗余传输，能够根据接收到的包，对缺失的包进行恢复（类似RAID）。对于一个TCP连接，需要四个参数：源IP/端口，目的IP/端口，任何一个改变都需要重新建立连接。QUIC则不需要这些，因为UDP并不需要来源信；它使用UUID来标识一个连接，只要这个UUID在，那么这个连接会话就能够继续（与HTTP会话有点像）。因此在不同网络，特别是移动网络之间的切换，都将保持稳定（参考：&lt;a class="link" href="http://Mosh" target="_blank" rel="noopener"&#10; &gt;Mosh&lt;/a&gt;）。目前Google的网站已经支持，并可以在Chrome浏览器的里面查看连接情况：chrome://net-internals/#quic。&lt;/p&gt;&#10;&lt;p&gt;通常说TCP是可靠连接，可用于数据流，复杂网络情况；UDP由于缺少确认机制等，属不可靠连接，通常应用于网络情况良好（内部）或者允许丢包的场景。事实上UDP也应用于游戏，VoIP等需要高效传输的场景。当网络状况糟糕时，使用TCP通信反而可能更差，因为需要更多步骤建立连接和确认。参考这里：&lt;a class="link" href="https://www.zhihu.com/question/20292749" target="_blank" rel="noopener"&#10; &gt;QQ 为什么采用 UDP 协议，而不采用 TCP 协议实现？&lt;/a&gt;。TCP连接是有状态的，服务端需要去维持，及&lt;a class="link" href="http://huoding.com/2013/12/31/316" target="_blank" rel="noopener"&#10; &gt;TIME_WAIT&lt;/a&gt;问题。如果连接一段时间没用，TCP并不能感知连接是否仍然有效，需要自定义心跳包，维持连接。UDP则是无连接状态的，只要知道目标IP及端口即可以发送。&lt;/p&gt;&#10;&lt;p&gt;UDP通信简单许多，不需要socket_connect和socket_connect，主动暴露一端（服务端）需要socket_bind。例如，服务端：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$socket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_server&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;udp://127.0.0.1:1113&amp;#34;&lt;/span&gt;, $errno, $errstr, &lt;span style="color:#a6e22e"&gt;STREAM_SERVER_BIND&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$socket) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$errstr&lt;/span&gt;&lt;span style="color:#e6db74"&gt; (&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$errno&lt;/span&gt;&lt;span style="color:#e6db74"&gt;)&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pkt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_recvfrom&lt;/span&gt;($socket, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $peer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$peer&lt;/span&gt;&lt;span style="color:#e6db74"&gt;,&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$pkt&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//客户端互相通信时，注释下面一行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_sendto&lt;/span&gt;($socket, &lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;D M j H:i:s Y&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $peer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($pkt &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sock &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_create&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;AF_INET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOCK_DGRAM&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOL_UDP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Ping !&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($msg);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;socket_sendto&lt;/span&gt;($sock, $msg, $len, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1113&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//sleep(30)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_recv&lt;/span&gt;( $sock , $reply , &lt;span style="color:#ae81ff"&gt;2045&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;MSG_WAITALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $reply;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($sock);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务端的代码里面有个stream_socket_sendto（或者socket_sendto），向客户端发送消息。UDP并不需要向客户端回复消息，这并像TCP在同一个连接里面回复，而是另一次UDP通信罢了。实际上，两个客户端之间就能够互相通信（分别使用不同端口），任何能够拿到对方IP和端口，都能够向其发送消息。复制客户端代码，更改目标IP和端口为服务端打印出来的信息，然后运行，原先的客户端也将收到消息。利用中间服务器交换两个客户端的IP和端口，以便直接通信，是NAT穿透常用的方法。&lt;/p&gt;&#10;&lt;p&gt;综上，使用TCP可以保证数据可靠传输，复用连接，比如请求-应答模型；使用UDP则可以更高效发送数据，但能容忍部分丢包的场景，比如视频画面；或者只发送不需响应的数据，比如日志；或者无需连接状态的场景（类似HTTP会话），减少服务器压力和客户端等待。当然，也可以在UDP基础上自定义传输规则，实现譬如Mosh或则TCP那样的应用。选择TCP或者UDP，应该综合考虑使用场景，网络，数据包大小，效率，安全等，而不是盲从字面上的“面向可靠的”或者“不可靠的”或者“高效的”。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/tennysonsky/article/details/44562435" target="_blank" rel="noopener"&#10; &gt;如何理解HTTP协议的 “无连接，无状态” 特点？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://ma.ttias.be/googles-quic-protocol-moving-web-tcp-udp/" target="_blank" rel="noopener"&#10; &gt;Google’s QUIC protocol: moving the web from TCP to UDP（&lt;/a&gt;&lt;a class="link" href="http://www.infoq.com/cn/articles/quic-google-protocol-web-platform-from-tcp-to-udp" target="_blank" rel="noopener"&#10; &gt;Google QUIC协议：从TCP到UDP的Web平台&lt;/a&gt;）&lt;br&gt;&#10;&lt;a class="link" href="http://zhihu.com/question/29705994/answer/46357120" target="_blank" rel="noopener"&#10; &gt;如何看待谷歌 Google 打算用 QUIC 协议替代 TCP/UDP？ – 回答作者: Trotyl Yu&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://mosh.org/#techinfo" target="_blank" rel="noopener"&#10; &gt;How Mosh works&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/regedit/articles/829725.html" target="_blank" rel="noopener"&#10; &gt;使用TCP协议的NAT穿透技术&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php-socket%e9%80%9a%e4%bf%a1/" target="_blank" rel="noopener"&#10; &gt;PHP Socket通信&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/http%e6%96%87%e4%bb%b6%e5%88%86%e5%9d%97%e4%b8%8a%e4%bc%a0%e4%b8%8b%e8%bd%bd/" target="_blank" rel="noopener"&#10; &gt;日志系统设计&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.codingnow.com/2016/03/reliable_udp.html" target="_blank" rel="noopener"&#10; &gt;可靠 UDP 传输&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E9%98%BB%E6%96%B7%E6%9C%8D%E5%8B%99%E6%94%BB%E6%93%8A" target="_blank" rel="noopener"&#10; &gt;DDOS（拒绝服务攻击）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/blognkliming/article/details/17181773" target="_blank" rel="noopener"&#10; &gt;php使用socket感悟–tcp和udp&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.binarytides.com/udp-socket-programming-in-php/" target="_blank" rel="noopener"&#10; &gt;UDP socket programming in php&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/18897917/does-webrtc-use-tcp-or-udp" target="_blank" rel="noopener"&#10; &gt;Does WebRTC use TCP or UDP?&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>日志系统设计</title><link>https://courages.us/%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</link><pubDate>Mon, 03 Oct 2016 22:35:33 +0800</pubDate><guid>https://courages.us/%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</guid><description>&lt;p&gt;日志系统是项目开发/运维当中非常重要的一部分，提供产品使用情况，跟踪调试信息等。以前都是各个项目各自实现日志记录，比如PHP、JAVA各自实现一套，如果要跨项目/服务器进行查询/跟踪/统计，则比较麻烦，比如Web后台–&amp;gt;业务模块–&amp;gt;基础组件，客户端–&amp;gt;公共接口–&amp;gt;业务模块等等。&lt;br&gt;&#10;目前的项目都是将日志写入本地，首先需要定义统一的规范：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;格式&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DateTime | ServerIP | ClientIP | PID | RequestID| Type | Level | Message| Code&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;解释&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DateTime：记录日志的当前时间戳&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ServerIP：当前服务器IP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ClientIP:客户端IP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PID：进程ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RequestID：交易号，即请求的唯一标识，使用uniqid(+UserCode)或UUID或，一次请求会有多条日志，，用于关联本次请求内的相关日志&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type：日志类型，比如统计，操作（审计），业务等&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Level：日志等级&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Message：日志内容，当为值为数组或者对象时转为JSON&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为RUNTIME时，表示运行日志，属性：自定义&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为HTTP时，表示来源请求，属性：Url，Method（Get/Post），Params，RemoteIP，UserAgent，ReferUrl[，Action，Method]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为REST时，表示外部调用，属性：Type（Http/Https），Url,Port，RequestParams，Response，RunTime；&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type为SQL时，表示SQL执行，属性：Sql，RunTime&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Code：标识码，记录错误码、响应码、统计码、版本、自定义信息，方便统计&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的RequestID由入口处自动产生，用于标识一次请求，关联所产生的所有日志，需要在各个项目之间传递。为了减少日志，Level通常为Info级别，避免产生过多日志。为了方便调试追踪，RequestID和Level也可以在其他参数中指明，比如HTTP头里面附加。&lt;br&gt;&#10;然后是日志收集：客户端收走日志系统，发送给日志系统服务端。&lt;br&gt;&#10;然后分析处理呈现：服务端将接收到的日志，发给处理其他组件分析处理，提供Web界面的查询系统。研发人员，可以错误信息，定位问题；获悉程序运行情况进行调优；大数据分析日志，得出产品使用情况；运维平台则可以进行业务报警。&lt;/p&gt;&#10;&lt;p&gt;日志产生由个语言依照规范自行实现，收集、保持则由&lt;a class="link" href="https://flume.apache.org/" target="_blank" rel="noopener"&#10; &gt;Flume&lt;/a&gt;和&lt;a class="link" href="http://kafka.apache.org/" target="_blank" rel="noopener"&#10; &gt;Kafka&lt;/a&gt;实现。Flume是一个分布式的日志收集、合并、移动系统，能够监控文件变化，将变化部分传输出去。Kafka是一个分布式的发布/订阅的消息流平台，包括Broker，Consumer，Producer都支持分布式，依赖&lt;a class="link" href="https://courages.us/php-zookeeper%e5%88%86%e5%b8%83%e5%bc%8f%e6%9c%8d%e5%8a%a1%e5%bc%80%e5%8f%91/" target="_blank" rel="noopener"&#10; &gt;Zookeeper&lt;/a&gt;实现。&lt;/p&gt;&#10;&lt;p&gt;在PHP上面的实现，一开始使用&lt;a class="link" href="https://logging.apache.org/log4php/" target="_blank" rel="noopener"&#10; &gt;log4php&lt;/a&gt;，看起来很美好，但是性能很差，对业务影响较大。决定再次简化，砍掉不必要的东西（Socket，邮件等等），在C语言开发的PHP日志扩展&lt;a class="link" href="https://github.com/Neeke/SeasLog" target="_blank" rel="noopener"&#10; &gt;SeasLog&lt;/a&gt;基础上在做开发，将日志文件保存在本地。为了减少日志所占用内存，每超过一定的大小的日志即进行保存，否则在最后进行保存，利用了Nginx的fastcgi_finish_request特性。生产上发现，每天产生的文件日志太大了，需要控制日志信息大小、等级，并及时清理。&lt;br&gt;&#10;对于Web后台，还结合FirePHP，将日志直接输出到浏览器，方便边运行变调试。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.bitstech.net/2014/01/07/log-best-practice/" target="_blank" rel="noopener"&#10; &gt;最佳日志实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://testing.googleblog.com/2013/06/optimal-logging.html" target="_blank" rel="noopener"&#10; &gt;Optimal Logging&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://neoremind.com/2016/05/flumekafka%E6%94%B6%E9%9B%86docker%E5%AE%B9%E5%99%A8%E5%86%85%E5%88%86%E5%B8%83%E5%BC%8F%E6%97%A5%E5%BF%97%E5%BA%94%E7%94%A8%E5%AE%9E%E8%B7%B5/" target="_blank" rel="noopener"&#10; &gt;Flume+Kafka收集Docker容器内分布式日志应用实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tech.meituan.com/mt-log-system-arch.html" target="_blank" rel="noopener"&#10; &gt;基于Flume的美团日志收集系统(一)架构和设计&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/news/2015/09/BookKeeper-Twitter" target="_blank" rel="noopener"&#10; &gt;Twitter是如何构建高性能分布式日志的&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dongxicheng.org/search-engine/log-systems/" target="_blank" rel="noopener"&#10; &gt;开源日志系统比较&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/articles/kafka-analysis-part-1" target="_blank" rel="noopener"&#10; &gt;Kafka剖析（一）：Kafka背景及架构介绍&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://blog.wilddog.com/?p=862" target="_blank" rel="noopener"&#10; &gt;基于Flume的野狗实时日志系统的演进和优化&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/EVODelavega/phpkafka" target="_blank" rel="noopener"&#10; &gt;EVODelavega/phpkafka&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tech.youzan.com/you-zan-tong-ri-zhi-ping-tai-chu-tan/" target="_blank" rel="noopener"&#10; &gt;有赞统一日志平台初探&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/yangbutao/article/details/8741977" target="_blank" rel="noopener"&#10; &gt;RabbitMQ和kafka从几个角度简单的对比&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000002532284" target="_blank" rel="noopener"&#10; &gt;Flume-ng的原理和使用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dataunion.org/19045.html" target="_blank" rel="noopener"&#10; &gt;利用flume+kafka+storm+mysql构建大数据实时系统&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>HTTP文件分块上传下载</title><link>https://courages.us/http%E6%96%87%E4%BB%B6%E5%88%86%E5%9D%97%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD/</link><pubDate>Sun, 02 Oct 2016 22:16:47 +0800</pubDate><guid>https://courages.us/http%E6%96%87%E4%BB%B6%E5%88%86%E5%9D%97%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD/</guid><description>&lt;p&gt;在开发中经常需要上传下载文件，涉及web页面，手机应用，线下服务器等，文件传输方式有HTTP，FTP，BT。。于是基于HTTP开发了统一文件上传下载接口。&lt;br&gt;&#10;由于上传涉及多端，网络状况复杂，需要能够支持断点续传，因此需要对文件进行分块和校验。&lt;br&gt;&#10;请求上传：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;chunk：当前块编号&lt;/li&gt;&#10;&lt;li&gt;chunks：文件分块总数&lt;/li&gt;&#10;&lt;li&gt;md5：整个文件md5&lt;/li&gt;&#10;&lt;li&gt;content：文件块内容&lt;/li&gt;&#10;&lt;li&gt;size：文件块大小&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务端返回:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;statu：状态，0失败，非0成功&lt;/li&gt;&#10;&lt;li&gt;chunk：需要上传的块编号&lt;/li&gt;&#10;&lt;li&gt;message：操作信息&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务端有几种情况&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1. 上传成功，md5已经存在，说明文件已存在，则返回上传成功，并结束上传，类似秒传&lt;/li&gt;&#10;&lt;li&gt;2. 上传成功，md5已经不存在，但当前文件块已经存在，说明该文件已经上传过一部分，则返回成功，并给出需要开始上传的块号，类似断点续传&lt;/li&gt;&#10;&lt;li&gt;3. 上传成功，文件块不存在，当前块号小于总块数减一，则返回上传成功，并给出下一块块号&lt;/li&gt;&#10;&lt;li&gt;4. 上传成功，文件块不存在，当前块号等于总块数减一，进行合并，校验成功，则返回上传成功，并结束上传&lt;/li&gt;&#10;&lt;li&gt;5. 上传成功，文件块不存在，当前块号等于总块数减一，进行合并，校验成功，则返回上传失败，从第一块重新开始上传&lt;/li&gt;&#10;&lt;li&gt;6. 上传失败，服务端返回失败，则根据错误信息重传&lt;/li&gt;&#10;&lt;li&gt;7. 上传失败，服务端没有返回，则重传当前块&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;客户端依据自定义的大小对文件进行切割，每次传递一个块，当服务端接收到当前块号为总块数减一则认为全部上传完毕，进行文件块合并，清除临时文件块，计算MD5，如果MD5与传递过来的相等则认为上传成功，否则失败，要求客户端从第一块重传。&lt;br&gt;&#10;这个是基于客户端顺序上传的，假如是并发上传呢？那么就需要在每个分块上传结束后触发合并，需要借助锁来管理。&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/upyun/js-multipart-upload/wiki/%E5%88%86%E5%9D%97%E4%B8%8A%E4%BC%A0%E8%AF%B4%E6%98%8E" target="_blank" rel="noopener"&#10; &gt;又拍云表单分块上传&lt;/a&gt;则分为3步骤：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1.初始化，上报文件信息&lt;/li&gt;&#10;&lt;li&gt;2.上传分块&lt;/li&gt;&#10;&lt;li&gt;3.上传结束，触发合并&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;而&lt;a class="link" href="http://fex.baidu.com/webuploader/" target="_blank" rel="noopener"&#10; &gt;百度的WebUploader&lt;/a&gt;则支持浏览器向服务端的断点续传，利用HTML5或Flash对文件进行分块，计算MD5。&lt;br&gt;&#10;HTTP分块下载，也就是断点续传下载，是根据HTTP1.1协议（RFC2616）中定义的HTTP头 Range和Content-Range字段来控制的：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1. 客户端在HTTP请求头里面指明Range，即开始下载位置&lt;/li&gt;&#10;&lt;li&gt;2. 服务端在HTTP响应头里面返回Content-Range，告知下载其实点和范围&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务端可以将文件MD5等加入Etag或自定义Header字段里面，HTTP客户端便可以分开请求数据，最后合并；否则永远都是从头开始。其实也可以把大文件切成多个小文件，再一个个下载回来合并。&lt;br&gt;&#10;有些web服务器直接支持文件上传和下载的断点续传，比如Nginx。&lt;/p&gt;&#10;&lt;p&gt;刚才的文件分块传输过程，有点像TCP通信，也有建立连接，分片，校验，重发，断开连接。&lt;br&gt;&#10;而这个将大任务分解为多个小任务进行处理的思想，即准备–&amp;gt;循环（并行）处理–&amp;gt;结束，可以应用到很多项目里面，比如大数据，爬虫。为Web管理系统写了jQuery插件用来处理的耗时任务，将一个耗时任务分解为多个循环请求，避免超时&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;1. prepare：服务端返任务标示ID，总步骤，及附加参数&lt;/li&gt;&#10;&lt;li&gt;2. process：根据返回参数进行循环请求&lt;/li&gt;&#10;&lt;li&gt;3. complete:循环完成，触发结束&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;后面又延伸出另外一个插件，支持任意顺序步骤的处理。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/kazaff/me.kazaff.article/blob/master/%E8%81%8A%E8%81%8A%E5%A4%A7%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.md" target="_blank" rel="noopener"&#10; &gt;聊聊大文件上传&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/blueimp/JavaScript-MD5" target="_blank" rel="noopener"&#10; &gt;md5 javascript&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/xifeijian/article/details/8712439" target="_blank" rel="noopener"&#10; &gt;HTTP协议－－断点续传&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.chinaunix.net/uid-25267728-id-4095080.html" target="_blank" rel="noopener"&#10; &gt;http断点续传的秘密&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.linuxprobe.com/nginx-upload-module.html" target="_blank" rel="noopener"&#10; &gt;nginx-upload-module模块实现文件断点续传&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/jony413/articles/4906854.html" target="_blank" rel="noopener"&#10; &gt;通过curl测试服务器是否支持断点续传&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>jQuery 插件开发</title><link>https://courages.us/jquery-%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91/</link><pubDate>Sat, 01 Oct 2016 22:43:35 +0800</pubDate><guid>https://courages.us/jquery-%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91/</guid><description>&lt;p&gt;最近开发一个前端图表模块，使用jQuery和Highchart开发，然后提供给其他人用，发现调用时要写太多代码，能不能一行搞定。之前开发过几个jQuery扩展，于是也做成jQuery扩展，调用时类似$(‘#chart’).warning(options)这样子，简洁了不少。&lt;br&gt;&#10;jQuery扩展有两种，一种是$(‘#element’).func()，使用了选择器，定义是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Plugin fucntions&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Plugin initial&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})(&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将PluginName这个插件注册到$.fn上面，另外一种$.func(options)，不绑定元素的，定义是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Plugin fucntions&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Plugin initial&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})(&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将PluginName直接挂在了$对象下面。&lt;br&gt;&#10;jQeury.extend方法可以用来扩展对象，也可以用来增加插件：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$(&amp;#39;＃el&amp;#39;).PluginName方式&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extend&lt;/span&gt;({&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Plugin initial&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//对原有的PluginName插件再进一步扩展，也可用于升级插件而不修改原有代码&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extend&lt;/span&gt;({&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;doSomething&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Plugin extend&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extend&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;, {});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$.PluginName方式&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extend&lt;/span&gt;({&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Plugin initial&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extend&lt;/span&gt;({&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;doSomething&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Plugin extend&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下是一个简单的jQuery插件模板，来自&lt;a class="link" href="https://github.com/jquery-boilerplate/jquery-boilerplate/wiki/Extending-jQuery-Boilerplate" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Project: &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Description: &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Author: &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * License: &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// the semi-colon before function invocation is a safety net against concatenated&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// scripts and/or other plugins which may not be closed properly.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ( &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;, window, document, &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// undefined is used here as the undefined global variable in ECMAScript 3 is&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// mutable (ie. it can be changed by someone else). undefined isn&amp;#39;t really being&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// passed in so we can ensure the value of it is truly undefined. In ES5, undefined&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// can no longer be modified.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// window is passed through as local variable rather than global&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// as this (slightly) quickens the resolution process and can be more efficiently&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// minified (especially when both are regularly referenced in your plugin).&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Create the defaults once&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;defaultPluginName&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;defaults&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;propertyName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// The actual plugin constructor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Plugin&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;element&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// jQuery has an extend method which merges the contents of two or&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// more objects, storing the result in the first object. The first object&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// is generally empty as we don&amp;#39;t want to alter the default options for&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// future instances of the plugin&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extend&lt;/span&gt;( {}, &lt;span style="color:#a6e22e"&gt;defaults&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) ;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_defaults&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;defaults&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;init&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Plugin&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;init&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Place initialization logic here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You already have access to the DOM element and the options via the instance,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// e.g., this.element and this.options&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You don&amp;#39;t need to change something below:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// A really lightweight plugin wrapper around the constructor,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// preventing against multiple instantiations and allowing any&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// public function (ie. a function whose name doesn&amp;#39;t start&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// with an underscore) to be called via the jQuery plugin,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// e.g. $(element).defaultPluginName(&amp;#39;functionName&amp;#39;, arg1, arg2)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;fn&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ( &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;arguments&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Is the first parameter an object (options), or was omitted,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// instantiate a new instance of the plugin.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;object&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;each&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Only allow the plugin to be instantiated once,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// so we check that the element has no plugin instantiation yet&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;plugin_&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// if it has no instance, create a new one,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// pass options to our plugin constructor,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// and store the plugin instance&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// in the elements jQuery data object.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;plugin_&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Plugin&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; ));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// If the first parameter is a string and it doesn&amp;#39;t start&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// with an underscore or &amp;#34;contains&amp;#34; the `init`-function,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// treat this as a call to a public method.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;string&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;init&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Cache the method call&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// to make it possible&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// to return a value&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;returns&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;each&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;instance&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;plugin_&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Tests that there&amp;#39;s already a plugin-instance&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// and checks that the requested public method exists&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;instance&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Plugin&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;instance&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;] &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Call the method of our plugin instance,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// and pass it the supplied arguments.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;returns&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;instance&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;instance&lt;/span&gt;, Array.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;slice&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Allow instances to be destroyed via the &amp;#39;destroy&amp;#39; method&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;destroy&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;plugin_&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pluginName&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// If the earlier cached method&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// gives a value back return the value,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// otherwise return this to preserve chainability.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;returns&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;returns&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}(&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;, window, document));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;根据这个就可以方便的开发jQuery插件了。&lt;br&gt;&#10;也可以使用jQuery.widget来开发一个插件，参考&lt;a class="link" href="https://learn.jquery.com/jquery-ui/widget-factory/extending-widgets/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//新插件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;widget&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;custom.superDialog&amp;#34;&lt;/span&gt;, {} );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//继承原有jQuery UI插件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;widget&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;custom.superDialog&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ui&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dialog&lt;/span&gt;, {} );&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除此之外，也可以自己写插件/模块：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// 将插件/模块定义在闭包私有空间里，加载时候就会立即执行，初始化&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;doSomething&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就可以调用了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;plugin&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PluginName&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plugin&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;doSomething&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以这样子：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MODULE&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;my&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;my&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;moduleMethod&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;// method override, has access to old through old_moduleMethod...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;};&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}(&lt;span style="color:#a6e22e"&gt;MODULE&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; {}));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;子模块&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;挂在MODULE这个对象&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;命名空间下面&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;MODULE&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;sub&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;模块多了就需要模块管理工具了，比如&lt;a class="link" href="http://requirejs.org/" target="_blank" rel="noopener"&#10; &gt;RequireJS&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//定义&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;myModule&amp;#39;&lt;/span&gt;, &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;], &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// module definition function&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// dependencies (foo and bar) are mapped to function parameters&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ( &lt;span style="color:#a6e22e"&gt;foo&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// return a value that defines the module export&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// (i.e the functionality we want to expose for consumption)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// create your module here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;doStuff&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Yay! Stuff&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;使用&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;([&lt;span style="color:#e6db74"&gt;&amp;#39;app/myModule&amp;#39;&lt;/span&gt;], &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt; ){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// start the main module which in-turn&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// loads other modules&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;module&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myModule&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;doStuff&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Javascript模块话加载可以参考&lt;a class="link" href="https://segmentfault.com/a/1190000000492678" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html" target="_blank" rel="noopener"&#10; &gt;JavaScript Module Pattern: In-Depth&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://learn.jquery.com/plugins/advanced-plugin-concepts/" target="_blank" rel="noopener"&#10; &gt;Advanced Plugin Concepts&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://addyosmani.com/resources/essentialjsdesignpatterns/book/" target="_blank" rel="noopener"&#10; &gt;Learning JavaScript Design Patterns&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.webdeveasy.com/jquery-plugin-pattern/" target="_blank" rel="noopener"&#10; &gt;jQuery Plugin Pattern&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://caibaojian.com/jquery-extend-and-jquery-fn-extend.html" target="_blank" rel="noopener"&#10; &gt;理解jquery的$.extend()、$.fn和$.fn.extend()&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.tutsplus.com/tutorials/making-use-of-jquery-uis-widget-factory--net-29606" target="_blank" rel="noopener"&#10; &gt;Making Use of jQuery UI’s Widget Factory&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://scotch.io/tutorials/building-your-own-javascript-modal-plugin" target="_blank" rel="noopener"&#10; &gt;Building Your Own JavaScript Modal Plugin&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://addyosmani.com/writing-modular-js/" target="_blank" rel="noopener"&#10; &gt;Writing Modular JavaScript With AMD, CommonJS &amp;amp; ES Harmony&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ruanyifeng.com/blog/2011/10/javascript_loading.html" target="_blank" rel="noopener"&#10; &gt;Javascript文件加载：LABjs和RequireJS&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000000591665" target="_blank" rel="noopener"&#10; &gt;jQuery Boilerplate——流行的jQuery插件开发模板&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>在Raspberry Pi上面运行Docker</title><link>https://courages.us/%E5%9C%A8raspberry-pi%E4%B8%8A%E9%9D%A2%E8%BF%90%E8%A1%8Cdocker/</link><pubDate>Fri, 30 Sep 2016 23:36:00 +0800</pubDate><guid>https://courages.us/%E5%9C%A8raspberry-pi%E4%B8%8A%E9%9D%A2%E8%BF%90%E8%A1%8Cdocker/</guid><description>&lt;p&gt;公司有个项目是运行在Raspberry Pi上面，这个项目涉及到Perl，Python，Java Applet，并且未来Pi的数量可能达到上千个。最近碰到了一样的代码遵循一样的部署脚本，在不同的树莓派上运行竟然到不同的结果。于是也想将Docker应用到树莓派上面去，使用docker主要优点：&lt;br&gt;&#10;1 消除环境差异，程序运行所依赖的环境已经一起打包，随身携带了&lt;br&gt;&#10;2 简化配置，只有docker相关配置，不再需要每个语言单独配置&lt;br&gt;&#10;3 重复利用&lt;br&gt;&#10;4 方便升级，之前有差异时，是重写镜像。。&lt;br&gt;&#10;5 方便管理，可以使用docker已有的工具来管理&lt;br&gt;&#10;6 性能接近原生应用&lt;/p&gt;&#10;&lt;p&gt;Raspberry Pi在jessie这个版本就已经支持了docker，检查版本：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ lsb_release -da&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;No LSB modules are available.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Distributor ID: Raspbian&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description: Raspbian GNU/Linux 8.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;jessie&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Release: 8.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Codename: jessie&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你的版本已经支持，直接执行以下命令就可以了：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -sSL https://get.docker.com | sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你的版本不支持，你需要升级系统或重新刷镜像，可以采用hypriot&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#下载&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://downloads.hypriot.com/hypriotos-rpi-v1.0.0.img.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#解压&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unzip hypriotos-rpi-v1.0.0.img.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#查找 SD card ID&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lsblk&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#查找类似/dev/mmcblk0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#弹出SD卡&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;umount /run/media/mac/8734-1E4C&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#将镜像写入 SD card&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dd &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;hypriotos-rpi-v1.0.0.img of&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/dev/mmcblk0 bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1m&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启动，默认的用户名/密码是pirate/hypriot。&lt;br&gt;&#10;当然也可以采用Debian或者是&lt;a class="link" href="https://wiki.alpinelinux.org/wiki/Raspberry_Pi" target="_blank" rel="noopener"&#10; &gt;Alpine Linux&lt;/a&gt;来&lt;a class="link" href="https://wiki.alpinelinux.org/wiki/Docker" target="_blank" rel="noopener"&#10; &gt;定制&lt;/a&gt;（Raspberry Pi仅支持 arm版本的系统，并且只能在arm平台上构建，或者&lt;a class="link" href="https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/" target="_blank" rel="noopener"&#10; &gt;这个&lt;/a&gt;）。&lt;br&gt;&#10;运行测试一下:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -d -p 80:80 hypriot/rpi-busybox-httpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问以下树莓派的IP，就会看到一个非常神器的网页，而这个容器仅仅几M。在&lt;a class="link" href="https://hub.docker.com/u/hypriot/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;可以看到基于hypriot的好几个镜像，也可以搜索其他的raspberry pi镜像。&lt;br&gt;&#10;现在我们使用hypriot/rpi-python来构建一个使用Python Selenium测试带有Java Applet的网页：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -idt -P --name web hypriot/rpi-python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker attach web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进入到容器里面，执行以下命令：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装openjdk&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install openjdk-7-jdk&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装Firefox&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install iceweasel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装Java Applet插件&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install icedtea-7-plugin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装虚拟桌面&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install xvfb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装Python包管理工具&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install python-pip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装selenium&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pip install selenium&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装Python虚拟桌面库&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pip install pyvirtualdisplay&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建测试test.py：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; selenium &lt;span style="color:#f92672"&gt;import&lt;/span&gt; webdriver&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; selenium.webdriver.common.keys &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Keys&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; time&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pyvirtualdisplay &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Display&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; selenium.webdriver.common.desired_capabilities &lt;span style="color:#f92672"&gt;import&lt;/span&gt; DesiredCapabilities&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; selenium.webdriver.firefox.firefox_binary &lt;span style="color:#f92672"&gt;import&lt;/span&gt; FirefoxBinary&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;display &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Display(visible&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;800&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;display&lt;span style="color:#f92672"&gt;.&lt;/span&gt;start()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;caps &lt;span style="color:#f92672"&gt;=&lt;/span&gt; DesiredCapabilities&lt;span style="color:#f92672"&gt;.&lt;/span&gt;FIREFOX&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;caps[&lt;span style="color:#e6db74"&gt;&amp;#34;marionette&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#caps[&amp;#34;binary&amp;#34;] = &amp;#34;/usr/bin/firefox&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;firefox_binary &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FirefoxBinary(&lt;span style="color:#e6db74"&gt;&amp;#34;/usr/bin/firefox&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; webdriver&lt;span style="color:#f92672"&gt;.&lt;/span&gt;FirefoxProfile()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_preference(&lt;span style="color:#e6db74"&gt;&amp;#34;security.enable_java&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt; )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_preference(&lt;span style="color:#e6db74"&gt;&amp;#34;plugin.state.java&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;driver &lt;span style="color:#f92672"&gt;=&lt;/span&gt; webdriver&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Firefox(firefox_profile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;fp,firefox_binary&lt;span style="color:#f92672"&gt;=&lt;/span&gt;firefox_binary)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;driver&lt;span style="color:#f92672"&gt;.&lt;/span&gt;maximize_window()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;driver&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;http://businessconnect.telus.com/bandwidth/en_us/index.html?voip=on&amp;amp;voiplines=1&amp;amp;testlength=15&amp;amp;codec=g711&amp;amp;_=1470641590&amp;amp;startTest=on&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sleep(&lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; driver&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find_element_by_class_name(&lt;span style="color:#e6db74"&gt;&amp;#34;sectiontitle18&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find_element_by_tag_name(&lt;span style="color:#e6db74"&gt;&amp;#34;span&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_attribute(&lt;span style="color:#e6db74"&gt;&amp;#34;innerHTML&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print mos&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;driver&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;display&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stop()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行测试用例：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python test.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果仅仅是这样子，是行不通的，Java Applet的安全询问弹窗超出了浏览器范围是点击不到的，需要更为强大的组件来做，比如。&lt;br&gt;&#10;这里采用取巧的方法，首先把pyvirtualdisplay相关代码注释掉，在界面上观察具体的执行效果，并点击安全询问，运行通过。然后取消注释，再次运行，就可以了。最后将运行通过的配置文件/root/.icedtea目录拷贝出来，放到其他的树莓派里面就可以了。&lt;br&gt;&#10;如果碰到报错”selenium.common.exceptions.WebDriverException: Can’t load the profile”，通常是说Firefox或selenium版本太低，如果检查都不是，需要修改WebDriver的超时时间&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nano /usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/webdriver.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;timeout从30秒改为120秒：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WebDriver&lt;/span&gt;(RemoteWebDriver):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# There is no native event support on Mac&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NATIVE_EVENTS_ALLOWED &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;platform &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;darwin&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, firefox_profile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;, firefox_binary&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;, timeout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改为容器后，提交变更：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@black-pearl:/home/pirate# docker ps -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;04762770df2d hypriot/rpi-python &lt;span style="color:#e6db74"&gt;&amp;#34;bash&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; days ago Up &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; days web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@black-pearl:/home/pirate# docker commit 04762770df2d hypriot/rpi-python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@black-pearl:/home/pirate# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行新镜像&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#docker run -idt -P --name web hypriot/rpi-python&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#映射程序目录和配置文件进去&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -idt -P --name web -v /home/pi:/home/pi -v /home/pi/.icedtea:/root/.icedtea hypriot/rpi-python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;程序正常运行后，可以将这个镜像打包：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker save -o hypriot.tar hypriot/rpi-python:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分发给其他树莓派运行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker load --input hypriot.tar&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -idt -P --name web -v /home/pi:/home/pi -v /home/pi/.icedtea:/root/.icedtea hypriot/rpi-python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样子便可以利用docker工具来管理这个应用程序，比起原本复杂的环境配置要简单很多。&lt;/p&gt;&#10;&lt;p&gt;在查找Pi可用镜像的时候，顺便发现了一个IOT（internet of things）管理平台：&lt;a class="link" href="https://resin.io/" target="_blank" rel="noopener"&#10; &gt;resin&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/docker/docker/pull/24815" target="_blank" rel="noopener"&#10; &gt;add support to install Docker on raspbian/jessie&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.hypriot.com/getting-started-with-docker-on-your-arm-device/" target="_blank" rel="noopener"&#10; &gt;Getting started with Docker on your Raspberry Pi&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.hypriot.com/getting-started-with-docker-and-linux-on-the-raspberry-pi/" target="_blank" rel="noopener"&#10; &gt;How to get Docker running on your Raspberry Pi using Linux&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.raspberrypi.org/forums/viewtopic.php?f=63&amp;amp;t=129320" target="_blank" rel="noopener"&#10; &gt;Getting selenium python to work on Raspberry Pi Model B&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用Docker Compose管理Docker容器</title><link>https://courages.us/%E4%BD%BF%E7%94%A8docker-compose%E7%AE%A1%E7%90%86docker%E5%AE%B9%E5%99%A8/</link><pubDate>Fri, 30 Sep 2016 00:10:36 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8docker-compose%E7%AE%A1%E7%90%86docker%E5%AE%B9%E5%99%A8/</guid><description>&lt;p&gt;&lt;a class="link" href="https://courages.us/%e6%9e%84%e5%bb%ba%e5%9f%ba%e4%ba%8edocker%e7%9a%84nginx-php-fpm-phalcon%e9%95%9c%e5%83%8f/" target="_blank" rel="noopener"&#10; &gt;上一篇&lt;/a&gt;创建了一个PHP的运行环境，现在需要一个MySQL服务，直接运行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name rocket-mysql -v /home/rocketfish/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root -d mysql:5.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就自动下载并得到一个mysql版本为5.7的服务镜像。&lt;br&gt;&#10;这时候，要运行一个Web服务我们需要运行两次的docker run才可以，如果还有更多的Web容器或其他的服务容器呢？&lt;br&gt;&#10;Docker官方提倡一个容器仅提供一个服务，多个服务/容器可以使用docker-compose来管理。&lt;br&gt;&#10;docker-compose本身是一个Python写的工具，可以直接通过pip安装：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# sudo pip install --upgrade pip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你本地并没有Python环境，也可以采用docker-compose的docker镜像来运行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# curl -L https://github.com/docker/compose/releases/download/1.8.0/run.sh &amp;gt; /usr/local/bin/docker-compose&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker-compose --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#开始下载镜像，建议用第一种&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看帮助&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker-compose -h&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Define and run multi-container applications with Docker.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Usage:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; docker-compose &lt;span style="color:#f92672"&gt;[&lt;/span&gt;-f &amp;lt;arg&amp;gt;...&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;options&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;COMMAND&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;ARGS...&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; docker-compose -h|--help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Options:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -f, --file FILE Specify an alternate compose file &lt;span style="color:#f92672"&gt;(&lt;/span&gt;default: docker-compose.yml&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -p, --project-name NAME Specify an alternate project name &lt;span style="color:#f92672"&gt;(&lt;/span&gt;default: directory name&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --verbose Show more output&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -v, --version Print version and exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -H, --host HOST Daemon socket to connect to&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --tls Use TLS; implied by --tlsverify&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --tlscacert CA_PATH Trust certs signed only by this CA&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --tlscert CLIENT_CERT_PATH Path to TLS certificate file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --tlskey TLS_KEY_PATH Path to TLS key file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --tlsverify Use TLS and verify the remote&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --skip-hostname-check Don&lt;span style="color:#e6db74"&gt;&amp;#39;t check the daemon&amp;#39;&lt;/span&gt;s hostname against the name specified&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; in the client certificate &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; example &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; your docker host&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; is an IP address&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Commands:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; build Build or rebuild services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bundle Generate a Docker bundle from the Compose file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config Validate and view the compose file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; create Create services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; down Stop and remove containers, networks, images, and volumes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; events Receive real time events from containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exec Execute a command in a running container&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; help Get help on a command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kill Kill containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logs View output from containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pause Pause services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; port Print the public port &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a port binding&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ps List containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pull Pulls service images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; push Push service images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart Restart services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rm Remove stopped containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run Run a one-off command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; scale Set number of containers &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start Start services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stop Stop services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; unpause Unpause services&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; up Create and start containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; version Show the Docker-Compose version information&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些命令包括了创建/启动/停止/暂停/继续运行容器。&lt;br&gt;&#10;首先要创建docker-compose.yml，这是一个&lt;a class="link" href="http://yaml.org/" target="_blank" rel="noopener"&#10; &gt;YAML&lt;/a&gt;格式的文档&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir docker&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd docker&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内容如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;version: &amp;#39;2&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: mysql:5.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &amp;#34;3306:3306&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_ROOT_PASSWORD: root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_DATABASE: web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_USER: root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MYSQL_PASSWORD: rootweb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./db/data:/var/lib/mysql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; web:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; depends_on:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &amp;#34;80:80&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WEB_DB_HOST: db:3306&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WEB_DB_PASSWORD: root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./web/html:/var/www/html/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; links:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - db&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的environment定义了环境变量，比如host的MAC，就可以在docker容器的系统变量里面得到，各个编程语言都有获取系统环境变量的方法。这些变量也可以组织起来放在文件里面加载进去，参考&lt;a class="link" href="https://docs.docker.com/compose/environment-variables/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;这里的volumes定义了要映射进容器的文件或文件夹或者数据容器，可以参考&lt;a class="link" href="https://docs.docker.com/engine/tutorials/dockervolumes/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。注意，多个容器共享同一个目录，会出现写冲突，比如MySQL，多个实例，数据目录需要分开。所以设计好你的程序，哪一部分是需要只读的（可以共享)，哪一部分是需要写的；写的部分是否可以放到各自临时目录，或者其他公共服务里面。&lt;br&gt;&#10;运行并查看&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker-compose up -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating network &lt;span style="color:#e6db74"&gt;&amp;#34;composeweb_default&amp;#34;&lt;/span&gt; with the default driver&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating composeweb_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating composeweb_web_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker-compose ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Name Command State Ports &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;------------------------------------------------------------------------------------&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;composeweb_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306-&amp;gt;3306/tcp &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;composeweb_web_1 /start.sh Up 443/tcp, 0.0.0.0:80-&amp;gt;80/tcp &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#也可以使用原来的命令&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;efbdaf257748 nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds 0.0.0.0:80-&amp;gt;80/tcp, 443/tcp composeweb_web_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;a6935d20911e mysql:5.7 &lt;span style="color:#e6db74"&gt;&amp;#34;docker-entrypoint.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; seconds 0.0.0.0:3306-&amp;gt;3306/tcp composeweb_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;docker-compose up -d ，将会在后台启动并运行所有的容器。&lt;br&gt;&#10;docker-compose仅仅提供了对多个docker服务的管理，仍然可以在这些容器上运行原来的docker命令。检查下web容器的IP：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker inspect composeweb_web_1 | grep IPAddress&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SecondaryIPAddresses&amp;#34;&lt;/span&gt;: null,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;IPAddress&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;IPAddress&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;172.18.0.3&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后访问：http://172.18.0.3/ 就可以看到web页面了。&lt;br&gt;&#10;如果想要停止服务，可以用docker-compose stop：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker-compose stop db&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Stopping composeweb_db_1 ... &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker-compose stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Stopping composeweb_web_1 ... &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次启动，得到相同名称的服务:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:/home/compose-web# docker-compose up -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting composeweb_db_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Starting composeweb_web_1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各个容器的名称也可以在配置文件里面通过参数container_name来指定。&lt;br&gt;&#10;docker-compose的配置还有很多其他的&lt;a class="link" href="https://docs.docker.com/compose/compose-file/" target="_blank" rel="noopener"&#10; &gt;参数&lt;/a&gt;，可以参考&lt;a class="link" href="https://docs.docker.com/compose/compose-file/#ipv4-address-ipv6-address" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。比如刚才我们通过docker inspect来查找容器IP，也可以配置成静态IP：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;version: &amp;#39;2&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app_net:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ipv4_address: 172.18.0.10&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ipv6_address: 2001:3984:3989::10&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; app_net:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver: bridge&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver_opts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; com.docker.network.enable_ipv6: &amp;#34;true&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ipam:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver: default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - subnet: 172.18.0.0/24&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gateway: 172.18.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - subnet: 2001:3984:3989::/64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gateway: 2001:3984:3989::1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以&lt;a class="link" href="https://docs.docker.com/compose/networking/" target="_blank" rel="noopener"&#10; &gt;自定义网络&lt;/a&gt;。&lt;br&gt;&#10;刚才我们的配置文件里面直接指定了镜像，也可以指定Dockerfile镜像构建，假如Dockerfile在web目录下面:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;build:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: ./web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者直接指明Dockerfile：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;build:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dockerfile: Dockerfile-alternate&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;实际上，docker-compose的配置已经覆盖了&lt;a class="link" href="https://docs.docker.com/engine/reference/builder/" target="_blank" rel="noopener"&#10; &gt;Dockerfile&lt;/a&gt;的配置项，也可以直接用于构建多个docker服务，比如指定运行的命令&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command: [/bin/bash]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的入口程序，如果不能持续运行的话，运行完成后，docker就会退出。所以如果你需要可以后台运行的docker容器，那么入口程序，就必须保持一个程序在前台运行，不退出，比如运行crontab的镜像，入口程序可以是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cron &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;cron这个程序是在后台运行的，如果不配合前台程序bash，容器执行玩cron就会退出了。其他运行crontab的容器，大都是强制一个程序在前台不退出，比如&lt;a class="link" href="https://www.ekito.fr/people/run-a-cron-job-with-docker/" target="_blank" rel="noopener"&#10; &gt;这个&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cron &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; tail -f /var/log/cron.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里需要注意一下，通过docker设置的environment values在容器内的cli下面执行时取不到的，比如printenv，使用cron后台运行时取不到外部设置的变量，但是手动执行时又可以。这些外部环境变量只能在ENTRYPOINT或者CMD所执行的shell里面去设置，比如在CMD执行start.sh:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;printenv | grep -E &lt;span style="color:#e6db74"&gt;&amp;#34;^HOST&amp;#34;&lt;/span&gt; &amp;gt; /root/env.conf &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cron &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker compose还可以跟&lt;a class="link" href="https://docs.docker.com/compose/swarm/" target="_blank" rel="noopener"&#10; &gt;Docker Swarm&lt;/a&gt;结合。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://docs.docker.com/compose/install/" target="_blank" rel="noopener"&#10; &gt;Install Docker Compose&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.docker.com/compose/wordpress/" target="_blank" rel="noopener"&#10; &gt;Quickstart: Docker Compose and WordPress&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/compose/yaml_file.md" target="_blank" rel="noopener"&#10; &gt;YAML 模板文件&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.linux.com/learn/introduction-docker-compose-tool-multi-container-applications" target="_blank" rel="noopener"&#10; &gt;Introduction to Docker Compose Tool for Multi-Container Applications&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/dockerfile/basic_structure.md" target="_blank" rel="noopener"&#10; &gt;Dockerfile基本结构&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://staxmanade.com/2016/05/how-to-get-environment-variables-passed-through-docker-compose-to-the-containers/" target="_blank" rel="noopener"&#10; &gt;How to Get Environment Variables Passed Through docker-compose to the Containers&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://ypereirareis.github.io/blog/2016/02/29/docker-crontab-environment-variables/" target="_blank" rel="noopener"&#10; &gt;Access environment variables from crontab into a docker container&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/27771781/how-can-i-access-docker-set-environment-variables-from-a-cron-job" target="_blank" rel="noopener"&#10; &gt;How can I access Docker set Environment Variables From a Cron Job&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/q/1010000000417103" target="_blank" rel="noopener"&#10; &gt;Dockerfile里指定执行命令用ENTRYPOING和用CMD有何不同？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/21553353/what-is-the-difference-between-cmd-and-entrypoint-in-a-dockerfile" target="_blank" rel="noopener"&#10; &gt;What is the difference between CMD and ENTRYPOINT in a Dockerfile?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://til.codes/docker-run-vs-cmd-vs-entrypoint/" target="_blank" rel="noopener"&#10; &gt;Docker difference between run, cmd, entrypoint commands&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>基于Docker的Nginx + PHP-FPM + Phalcon镜像</title><link>https://courages.us/%E6%9E%84%E5%BB%BA%E5%9F%BA%E4%BA%8Edocker%E7%9A%84nginx-php-fpm-phalcon%E9%95%9C%E5%83%8F/</link><pubDate>Wed, 28 Sep 2016 23:34:40 +0800</pubDate><guid>https://courages.us/%E6%9E%84%E5%BB%BA%E5%9F%BA%E4%BA%8Edocker%E7%9A%84nginx-php-fpm-phalcon%E9%95%9C%E5%83%8F/</guid><description>&lt;p&gt;&lt;a class="link" href="https://courages.us/ubuntu-16-04-%e4%b8%8a%e5%ae%89%e8%a3%85docker/" target="_blank" rel="noopener"&#10; &gt;上一篇&lt;/a&gt;简单介绍了Docker的安装，运行，这一篇来构建一个基于Nginx和PHP-FPM的Phalcon镜像。在官方找了以下，单独的Nginx和PHP镜像更加流行，混合的反倒不是很受欢迎。其实官方并不提倡在一个容器里面运行多个服务，最好是一个容器只对外提供一个服务：一个容器启动时仅仅运行一个命令（其实里面可以包含多个），也方便部署扩展升级。多个服务之间可以使用&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/compose/yaml_file.md" target="_blank" rel="noopener"&#10; &gt;Docker Compose&lt;/a&gt;来管理。但是Docker并不阻止创建包含多个服务器的镜像，为了方便，所以我们仍然可以自己构建。&lt;br&gt;&#10;构建镜像可以有好几种方式，比如基于&lt;a class="link" href="https://hub.docker.com/_/alpine/" target="_blank" rel="noopener"&#10; &gt;Alpine Linux&lt;/a&gt;或&lt;a class="link" href="https://github.com/phusion/baseimage-docker" target="_blank" rel="noopener"&#10; &gt;phusion/baseimage-docker&lt;/a&gt;构建，或者基于Ubuntu，CentOS等构建，又或者在PHP，Nginx的基础镜像上构建。注意：如果要采用Ubuntu或者CentOS构建，可能需要一些额外的&lt;a class="link" href="http://phusion.github.io/baseimage-docker/" target="_blank" rel="noopener"&#10; &gt;工作&lt;/a&gt;，以便保持镜像轻量稳定运行。&lt;br&gt;&#10;这里采用已有的&lt;a class="link" href="https://hub.docker.com/r/richarvey/nginx-php-fpm/" target="_blank" rel="noopener"&#10; &gt;richarvey/nginx-php-fpm&lt;/a&gt;来构建，它是一个基于&lt;a class="link" href="https://hub.docker.com/_/nginx/" target="_blank" rel="noopener"&#10; &gt;Nginx官方镜像&lt;/a&gt;来构建的。&lt;br&gt;&#10;从&lt;a class="link" href="https://github.com/ngineered/nginx-php-fpm" target="_blank" rel="noopener"&#10; &gt;Github&lt;/a&gt;上拉取相关文件从Dockerfile构建：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo git clone https://github.com/ngineered/nginx-php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo docker build -t nginx-php-fpm:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于Dockerfile的相关解释，可以参考&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/dockerfile/basic_structure.md" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。当然也可以直接拉取镜像使用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo docker pull richarvey/nginx-php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 也可以直接运行，会自动拉取&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#$ sudo docker run -d richarvey/nginx-php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看本地的镜像，连单独的nginx也来了：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx-php-fpm latest 4fc9ac9f2945 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; hours ago 228.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx mainline-alpine 00bc1e841a8f &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; days ago 54.21 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的mainline-alpine是指基于&lt;a class="link" href="https://alpinelinux.org/" target="_blank" rel="noopener"&#10; &gt;Alpine Linux&lt;/a&gt;构建的。Alpine Linux是一个仅有5M大小的linux系统，采用apk add/search来安装/查找相应软件，有许多镜像都是基于它构建的，官方PHP镜像也有基于它构建的Docker镜像。&lt;br&gt;&#10;然后运行nginx-php-fpm：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d richarvey/nginx-php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;docker inspect命令用来查看容器的相关信息，查看下分配的IP：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker inspect web | grep IPAddress&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SecondaryIPAddresses&amp;#34;&lt;/span&gt;: null,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;IPAddress&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;172.17.0.2&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;IPAddress&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;172.17.0.2&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在浏览器里面访问：http://172.17.0.2/就可以看到phpinfo的页面。到这里，Nginx + PHP的web容器就已经运行起来了，对应的Nginx和PHP进程可以在宿主机器上直接查看：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# ps aux | grep nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18167&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;13696&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4300&lt;/span&gt; pts/6 S 01:47 0:00 nginx: master process /usr/sbin/nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18168&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18169&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18170&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18171&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18172&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;14144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1868&lt;/span&gt; pts/6 S 01:47 0:00 nginx: worker process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18190&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;21292&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1012&lt;/span&gt; pts/18 S+ 01:47 0:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# ps aux | grep php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18166&lt;/span&gt; 0.0 0.2 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;23364&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: master process &lt;span style="color:#f92672"&gt;(&lt;/span&gt;/etc/php5/php-fpm.conf&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18173&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8620&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: pool www&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18174&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8620&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: pool www&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemd+ &lt;span style="color:#ae81ff"&gt;18175&lt;/span&gt; 0.0 0.1 &lt;span style="color:#ae81ff"&gt;167880&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8620&lt;/span&gt; pts/6 S 01:47 0:00 php-fpm: pool www&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root &lt;span style="color:#ae81ff"&gt;18192&lt;/span&gt; 0.0 0.0 &lt;span style="color:#ae81ff"&gt;21292&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1032&lt;/span&gt; pts/18 S+ 01:47 0:00 grep --color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto php-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来要为这个容器添加Phalcon扩展。首先要进入容器里面，使用docker attach命令进入：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker attach web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果在这里等了半天进不去。。。。查看下当前镜像入口程序：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;94176348a939 nginx-php-fpm &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个容器启动的时候运行的是start.sh这个脚本，这个脚本运行了&lt;a class="link" href="http://supervisord.org/" target="_blank" rel="noopener"&#10; &gt;Supervisor&lt;/a&gt;工具。于是重新启动容器，运行/bin/bash&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#终止容器运行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#删除容器&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#重新运行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i nginx-php-fpm /bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ea21e10df702644a83ed75930b30c7764a786c4feabdf17cd868f86640137c47&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ea21e10df702 nginx-php-fpm &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/bash&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker attach web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#进来了&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bin etc lib media proc run srv sys usr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dev home linuxrc mnt root sbin start.sh tmp var&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就可以进去了。&lt;br&gt;&#10;先安装编译相关工具包：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add php5-dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add gcc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add autoconf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# apk --no-cache add libc-dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;1/2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Installing musl-dev &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.1.14-r12&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;2/2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Installing libc-dev &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.7-r0&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OK: &lt;span style="color:#ae81ff"&gt;334&lt;/span&gt; MiB in &lt;span style="color:#ae81ff"&gt;106&lt;/span&gt; packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译安装Phalcon：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# cd /home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# git clone --depth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; git://github.com/phalcon/cphalcon.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# cd cphalcon/build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# ./install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# ls -la /usr/lib/php5/modules/ | grep phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rwxr-xr-x &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; root root &lt;span style="color:#ae81ff"&gt;5045264&lt;/span&gt; Sep &lt;span style="color:#ae81ff"&gt;28&lt;/span&gt; 17:34 phalcon.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改PHP扩展的配置：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# cd /etc/php5/conf.d/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# vi phalcon.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#添加以下内容&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#extension=phalcon.so&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#检查扩展是否加载成功&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# php -i | grep phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/etc/php5/conf.d/phalcon.ini,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; enabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.db.escape_identifiers &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.db.force_casting &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.cast_on_hydrate &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.column_renaming &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.enable_implicit_joins &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.enable_literals &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.events &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.exception_on_failed_save &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.ignore_unknown_columns &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.late_state_binding &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.not_null_validations &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon.orm.virtual_foreign_keys &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OLDPWD &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; /home/cphalcon/build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;_SERVER&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;OLDPWD&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; /home/cphalcon/build&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;_ENV&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;OLDPWD&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;gt; /home/cphalcon/build&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载成功了，需要保持本次镜像变更。首先退出容器：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# cd /home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#删除各种不必要的东西，比如gcc&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# rm -rf cphalcon/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash-4.3# exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后查看版本并提交变更：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ea21e10df702 nginx-php-fpm &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/bash&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt; minutes ago Exited &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker commit ea2 nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sha256:bb388df328ecc33fac02dba69759d5c992a145f650a0e5b20ca29a4b122fa933&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;docker commit命令可以用来提交变更，ea2是container id的前三位，也可以写全；然后跟的是要提交的镜像。这里提交到phalcon这个标签下，以便与原来的区分开。查看所有镜像，发现有两个不同的标签：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx-php-fpm phalcon bb388df328ec &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; seconds ago 364.4 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx-php-fpm latest 4fc9ac9f2945 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; hours ago 228.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;采用新镜像来运行，这里要讲程序运行入口改回/start.sh，以便能正常启动Nginx和PHP-FPM：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i nginx-php-fpm:phalcon /start.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deecb19467cda2676b24248e3f55970a2481255c6022a80ffbf5087792ccb559&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deecb19467cd nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;入口程序改变了，需要再提交一次变更：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c7600e62733d nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt; seconds ago Exited &lt;span style="color:#f92672"&gt;(&lt;/span&gt;137&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; seconds ago web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker commit c76 nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sha256:1c97ee169a551dd8441f42b40beafd102c71f3e887e2317dc11ce0ef136ceaf0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行最终的镜像：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cb5b0c9e55913a538539e46c53ac7905b21def84a05eb00ef81c4b500853576c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cb5b0c9e5591 nginx-php-fpm:phalcon &lt;span style="color:#e6db74"&gt;&amp;#34;/start.sh&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; seconds ago Up &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; seconds 80/tcp, 443/tcp web&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问http://172.17.0.2/，便可以在页面找到phalcon扩展。&lt;br&gt;&#10;通常我们会将程序和数据分开，挂载外部文件目录到容器里面去：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker stop web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker rm web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;web&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name web -d -t -i -v /home/docker/nginx-php-fpm/src:/var/www/html/ nginx-php-fpm:phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ffd64793fe8e7a2a95b68f514e221b7ec3b6cadfe668c016f55a7bb6d48bc702&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;-v参数可以用来挂载目录或者文件，可以又多个-v参数。&lt;br&gt;&#10;刚才容器里面做的那些已经添加到&lt;a class="link" href="https://github.com/llitllie/nginx-php-fpm-phalcon" target="_blank" rel="noopener"&#10; &gt;Dockerfile里&lt;/a&gt;面去，你直接使用它来构建。&lt;br&gt;&#10;至此Nginx + PHP-FPM + Phalcon镜像构建完成，介绍绍了如何进入容器，提交变更，网络访问和文件挂载。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://phusion.github.io/baseimage-docker/" target="_blank" rel="noopener"&#10; &gt;A minimal Ubuntu base image modified for Docker-friendliness&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://hub.docker.com/r/eboraas/phalcon/~/dockerfile/" target="_blank" rel="noopener"&#10; &gt;eboraas/phalcon&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dockone.io/article/117" target="_blank" rel="noopener"&#10; &gt;基于Docker的PHP开发环境&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.newmediacampaigns.com/blog/docker-for-php-developers" target="_blank" rel="noopener"&#10; &gt;Docker for PHP Developers&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://avnpc.com/pages/build-php-develop-env-by-docker" target="_blank" rel="noopener"&#10; &gt;Docker在PHP项目开发环境中的应用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/yeasy/docker_practice/blob/master/cases/supervisor.md" target="_blank" rel="noopener"&#10; &gt;使用 Supervisor 来管理进程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php-%e6%a1%86%e6%9e%b6phalcon/" target="_blank" rel="noopener"&#10; &gt;PHP C扩展框架Phalcon&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/news/2016/01/Alpine-Linux-5M-Docker" target="_blank" rel="noopener"&#10; &gt;Alpine Linux，一个只有5M的Docker镜像&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Ubuntu 16.04 上安装Docker</title><link>https://courages.us/ubuntu-16-04-%E4%B8%8A%E5%AE%89%E8%A3%85docker/</link><pubDate>Wed, 28 Sep 2016 21:32:11 +0800</pubDate><guid>https://courages.us/ubuntu-16-04-%E4%B8%8A%E5%AE%89%E8%A3%85docker/</guid><description>&lt;p&gt;Docker是一个轻量级的虚拟化容器技术，既可以为不同应用程序提供了隔离空间（内存，资源，网络），又可以将应用程序与环境一起打包，发布到其他机器上，避免环境的差异，这点像&lt;a class="link" href="https://courages.us/windows-8-%e5%ae%89%e8%a3%85vagrant%e5%92%8cvirtualbox/" target="_blank" rel="noopener"&#10; &gt;Vagrant&lt;/a&gt;。 但是，它又与传统的虚拟机不容（如VirtualBox），它的应用程序仍然是跑在宿主机上面的，并且镜像里面通常仅包含所必须的组件而非完整的系统，因此拥有极高的性能。这又有点像Python的Virtual Environment，不过Docker更加强大，本质是是个Linux，可以打包的不同语言的应用程序。&lt;br&gt;&#10;Docker要求linux内核版本大于3.10，可以在通过以下命令查看是否支持&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ uname -r&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4.4.0-38-generic&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要先更新以下apt仓库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo apt-get update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo apt-get install apt-transport-https ca-certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;/sell&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;检查以下是否已经创建Docker软件仓库文件,如果没有需要手动创建，并添加以下内容&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# cat /etc/apt/sources.list.d/docker.list&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deb https://apt.dockerproject.org/repo ubuntu-xenial main&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;/sell&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;确认是否配置成功&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# sudo apt-get update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# apt-cache policy docker-engine&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker-engine:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Installed: 1.12.1-0~xenial&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Candidate: 1.12.1-0~xenial&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Version table:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; *** 1.12.1-0~xenial &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; /var/lib/dpkg/status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1.12.0-0~xenial &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1.11.2-0~xenial &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1.11.1-0~xenial &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1.11.0-0~xenial &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt; https://apt.dockerproject.org/repo ubuntu-xenial/main amd64 Packages&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Docker容器建立在Auf文件系统之上，以便支持将不同的目录挂载到同一虚拟文件系统下面，并设置不同的读写权限。需要安装linux-image-extra：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo apt-get install linux-image-extra-&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;uname -r&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt; linux-image-extra-virtual&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;/sell&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;现在可以开始安装Docker了：&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo apt-get install docker-engine&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo service docker start&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;试运行一下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run hello-world&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hello from Docker!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;This message shows that your installation appears to be working correctly.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;To generate this message, Docker took the following steps:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1. The Docker client contacted the Docker daemon.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 2. The Docker daemon pulled the &lt;span style="color:#e6db74"&gt;&amp;#34;hello-world&amp;#34;&lt;/span&gt; image from the Docker Hub.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3. The Docker daemon created a new container from that image which runs the&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; executable that produces the output you are currently reading.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 4. The Docker daemon streamed that output to the Docker client, which sent it&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; to your terminal.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;To try something more ambitious, you can run an Ubuntu container with:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $ docker run -it ubuntu bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Share images, automate workflows, and more with a free Docker Hub account:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; https://hub.docker.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;For more examples and ideas, visit:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; https://docs.docker.com/engine/userguide/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你本地没有hello-world这个镜像，它是会自动去Docker官网上下载的。&lt;br&gt;&#10;查看最近运行过的容器，不加参数-l，是查看正在运行的容器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1931765938dc hello-world &lt;span style="color:#e6db74"&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; minutes ago Exited &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; minutes ago suspicious_lichterman&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行镜像的时候也可以指定名称（而不是suspicious_lichterman）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name hello hello-world&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hello from Docker!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker ps -l&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;e4773606e6cf hello-world &lt;span style="color:#e6db74"&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; seconds ago Exited &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; seconds ago hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是再次运行同样名称为hello的容器时会报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker run --name hello hello-world&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker: Error response from daemon: Conflict. The name &lt;span style="color:#e6db74"&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt; is already in use by container e4773606e6cf4222b786d5301ab38e4dddb90e11a0358f64d33109bf829f0b5a. You have to remove &lt;span style="color:#f92672"&gt;(&lt;/span&gt;or rename&lt;span style="color:#f92672"&gt;)&lt;/span&gt; that container to be able to reuse that name..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;See &lt;span style="color:#e6db74"&gt;&amp;#39;docker run --help&amp;#39;&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候需要先把旧的给删掉，再运行就不会了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker rm hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过Docker stop停止运行指定容器。&lt;br&gt;&#10;查看本地的Docker镜像&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;root@thinkpad:~# docker images&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REPOSITORY TAG IMAGE ID CREATED SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx-php-fpm phalcon 1c97ee169a55 &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; hours ago 364.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx-php-fpm latest 4fc9ac9f2945 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; hours ago 228.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ubuntu 16.04 c73a085dc378 &lt;span style="color:#ae81ff"&gt;47&lt;/span&gt; hours ago 127.1 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ubuntu latest c73a085dc378 &lt;span style="color:#ae81ff"&gt;47&lt;/span&gt; hours ago 127.1 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx mainline-alpine 00bc1e841a8f &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; days ago 54.21 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysql 5.7 4b3b6b994512 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; weeks ago 384.5 MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hello-world latest c54a2cc56cbb &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; weeks ago 1.848 kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里先简单的介绍Docker的安装、运行，后续将介绍Docker命令行交互，网络，文件存储等。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://Docker%20Overview" target="_blank" rel="noopener"&#10; &gt;Docker Overview&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/articles/docker-containers" target="_blank" rel="noopener"&#10; &gt;Docker：利用Linux容器实现可移植的应用部署&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.docker.com/engine/installation/linux/ubuntulinux/" target="_blank" rel="noopener"&#10; &gt;Installation&lt;br&gt;&#10;on Ubuntu&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/news/2013/04/Docker" target="_blank" rel="noopener"&#10; &gt;Docker：具备一致性的自动化软件部署&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.gitbook.com/book/yeasy/docker_practice/details" target="_blank" rel="noopener"&#10; &gt;Docker — 从入门到实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000000448808" target="_blank" rel="noopener"&#10; &gt;Docker简介与入门&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/articles/analysis-of-docker-file-system-aufs-and-devicemapper" target="_blank" rel="noopener"&#10; &gt;剖析Docker文件系统：Aufs与Devicemapper&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/21889053/what-is-the-runtime-performance-cost-of-a-docker-container" target="_blank" rel="noopener"&#10; &gt;What is the runtime performance cost of a Docker container&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/strbalaji/docker-26650285?next_slideshow=1" target="_blank" rel="noopener"&#10; &gt;Docker – The Linux Container&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://betacz.com/2014/05/21/vagrant-met-docker-2/" target="_blank" rel="noopener"&#10; &gt;当流浪者(Vagrant)遇见码头工人(Docker): 实战&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PagerDuty Integration Development</title><link>https://courages.us/pagerduty-integration-development/</link><pubDate>Wed, 18 May 2016 22:35:05 +0800</pubDate><guid>https://courages.us/pagerduty-integration-development/</guid><description>&lt;iframe src="//view.officeapps.live.com/op/embed.aspx?src=http%3A%2F%2Fcourages.us%2Fwp-content%2Fuploads%2F2016%2F05%2FPagerDuty-Integration-Development.pptx" title="Embedded Document" class="ead-iframe" style="width: 100%;height: 100%;border: none;position: absolute;left: 0;top: 0;"&gt;&lt;/iframe&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2016/05/PagerDuty-Integration-Development.pptx" target="_blank" rel="noopener"&#10; &gt;Download&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.pagerduty.com/" target="_blank" rel="noopener"&#10; &gt;PagerDuty&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php%e6%b5%8b%e8%af%95%e6%a1%86%e6%9e%b6%e5%88%9d%e6%8e%a2%ef%bc%9aphpunit/" target="_blank" rel="noopener"&#10; &gt;PHP测试框架初探：PHPUnit&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Centos 6.4 安装 Python 2.7</title><link>https://courages.us/centos-6-4-%E5%AE%89%E8%A3%85-python-2-7/</link><pubDate>Sat, 16 Apr 2016 12:10:31 +0800</pubDate><guid>https://courages.us/centos-6-4-%E5%AE%89%E8%A3%85-python-2-7/</guid><description>&lt;p&gt;终于又开始学Python了，不过这次是在Centos 6.4 上面，也碰到了好多问题。Centos6.4&lt;br&gt;&#10;并不能通过yum安装Python 2.7，系统自带的yum等使用的都是Python2.6.6，将系统的Python软链接指向2.7版本会有各种问题，包括依赖库等等；或者只能创建新的可执行命令，如Python27。最终按照&lt;a class="link" href="https://github.com/h2oai/h2o-2/wiki/Installing-python-2.7-on-centos-6.3.-Follow-this-sequence-exactly-for-centos-machine-only" target="_blank" rel="noopener"&#10; &gt;这篇&lt;/a&gt;文章的介绍成功安装了Python2.7。&lt;br&gt;&#10;首先安装相关的工具，要不然等下编译Python会报各种各样的错：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo yum groupinstall &lt;span style="color:#e6db74"&gt;&amp;#34;Development tools&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo yum install zlib-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo yum install bzip2-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo yum install openssl-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo yum install ncurses-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sudo yum install sqlite-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后下载Python并安装，注意这里是make altinstall而不是make install，参考&lt;a class="link" href="https://docs.python.org/2/using/unix.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ wget https://www.python.org/ftp/python/2.7.11/Python-2.7.11.tar.xz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ tar xf Python-2.7.11.tar.xz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd Python-2.7.11&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo make &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo make altinstall&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查一下是不是安装到了/usr/local/bin/python2.7下面去了，后面Python 2.7相关的库也将安装到这里&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -ltr /usr/local/bin/python*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查一下Python2.6是不是还在/usr/bin/下面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -ltr /usr/bin/python*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查一下系统路径变量PATH，保证/usr/local/bin在/usr/bin之前，然后将Python的软链接指向2.7。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ echo $PATH&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ln -s /usr/local/bin/python2.7 /usr/local/bin/python&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样子普通用户登录的时候就可以使用Python2.7了，而root用户（sudo）仍然使用Python2.6，yum等才不会出错。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ which python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/bin/python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ python -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Python 2.7.11&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo -s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;which python&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#/usr/bin/python&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#Python 2.6.6&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装Python 2.7的包管理工具&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /usr/local/bin/python2.7 ez_setup.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo /usr/local/bin/easy_install-2.7 pip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查一下是不是对了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ which pip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/bin/pip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ which easy_install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/bin/easy_install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在普通用户下面操作使用easy_install 就是安装到Python2.7的目录下面去了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ easy_install requests&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候会报错，因为相关的Python 2.7目录并没有写的权限&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo chmod &lt;span style="color:#ae81ff"&gt;664&lt;/span&gt; /usr/local/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo /usr/local/bin/easy_install-2.7 requests&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：如果是在root用户或者sudo命令下，使用的仍然是Python 2.6，所以必须要指明使用那个版本的easy_install。&lt;br&gt;&#10;接下来就可以愉快的使用pip安装Python2.7相关的库了。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/h2oai/h2o-2/wiki/Installing-python-2.7-on-centos-6.3.-Follow-this-sequence-exactly-for-centos-machine-only" target="_blank" rel="noopener"&#10; &gt;Installing python 2.7 on centos 6.3. Follow this sequence exactly for centos machine only&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-python-2-7-6-and-3-3-3-on-centos-6-4" target="_blank" rel="noopener"&#10; &gt;How To Set Up Python 2.7.6 and 3.3.3 on CentOS 6.4&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://toomuchdata.com/2014/02/16/how-to-install-python-on-centos/" target="_blank" rel="noopener"&#10; &gt;How to install Python 2.7 and Python 3.3 on CentOS 6&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/jcjc918/article/details/11022345" target="_blank" rel="noopener"&#10; &gt;Centos 6.4 python 2.6 升级到 2.7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://segmentfault.com/a/1190000000654227" target="_blank" rel="noopener"&#10; &gt;CENTOS 6.5 安装 Python 2.7 总结&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/16018463/difference-in-details-between-make-install-and-make-altinstall" target="_blank" rel="noopener"&#10; &gt;Difference in details between “make install” and “make altinstall”&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/common-python-tools-using-virtualenv-installing-with-pip-and-managing-packages" target="_blank" rel="noopener"&#10; &gt;Common Python Tools: Using virtualenv, Installing with Pip, and Managing Packages&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>分布式系统</title><link>https://courages.us/%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/</link><pubDate>Sat, 16 Apr 2016 10:50:33 +0800</pubDate><guid>https://courages.us/%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/</guid><description>&lt;p&gt;好久以前写的了。在InfoQ上学习了&lt;a class="link" href="http://www.infoq.com/cn/presentations/design-and-implementation-of-distributed-monitoring-system" target="_blank" rel="noopener"&#10; &gt;分布式监控系统的设计与实现&lt;/a&gt;、&lt;a class="link" href="http://www.infoq.com/cn/presentations/technology-of-weixin-moments" target="_blank" rel="noopener"&#10; &gt;微信朋友圈技术之道&lt;/a&gt;，在架构设计的基础思想并不复杂。&lt;br&gt;&#10;首先是微信朋友圈技术之道，介绍了微信朋友圈团队的开发，团队仅４个人，因为他们站在巨人的肩膀上：&lt;br&gt;&#10;基础环境&lt;br&gt;&#10;全部才用C＋＋开发&lt;br&gt;&#10;混合部署普通服务器&lt;br&gt;&#10;海量带宽&lt;/p&gt;&#10;&lt;p&gt;强大的基础设施&lt;br&gt;&#10;腾讯CDN，图片和视频上传、存储、分发&lt;br&gt;&#10;RPC框架&lt;br&gt;&#10;Key－Value（KV）存储系统&lt;br&gt;&#10;强大、方便、灵活的部署系统&lt;br&gt;&#10;强大的RPC框架&lt;br&gt;&#10;C＋＋的框架&lt;br&gt;&#10;支持protobuf描述接口&lt;br&gt;&#10;支持进程/线程/协程多种模式：支持数十万的并发协程，方便编写和调试“同步”的网络调用和服务&lt;br&gt;&#10;从CGI到叶子服务器，全系统透明支持过载保护和QOS&lt;br&gt;&#10;为每次CGI调用自动生成全系统调用关系图&lt;br&gt;&#10;每个服务自动内建500多个监控项&lt;br&gt;&#10;高性能Key-value存储系统&lt;br&gt;&#10;三机一组，三机间支持数据一致性，容忍一台机器出错、自动切换&lt;br&gt;&#10;三机分布在一个数据中心的三个独立园区，在任意一个园区提供本区读写服务，容忍一个园区网络隔离&lt;/p&gt;&#10;&lt;p&gt;微信架构&lt;br&gt;&#10;接入层，维持长连接，避免重复连接开销；推送消息&lt;br&gt;&#10;逻辑层，注册/登录，消息，朋友圈，LBS；批处理，群聊，通知，好友推荐&lt;br&gt;&#10;存储代理层，账号，消息，关系链，朋友圈，群管理&lt;br&gt;&#10;存储层，Key-value存储&lt;br&gt;&#10;性能水平扩展（sharding）&lt;br&gt;&#10;相册，按照用户做水平扩展&lt;br&gt;&#10;发表，按照发表key做水平扩展&lt;br&gt;&#10;评论，按照评论key做水平扩展&lt;br&gt;&#10;时间线，按照用户做水平扩展&lt;/p&gt;&#10;&lt;p&gt;发表流程&lt;br&gt;&#10;上传图片到CDN，查找最近节点&lt;br&gt;&#10;调用朋友圈CGI&lt;br&gt;&#10;添加新发表&lt;br&gt;&#10;在相册增加新发表索引&lt;br&gt;&#10;添加时间线更新任务，批处理，给好友时间线添加新索引&lt;br&gt;&#10;返回发表成功&lt;/p&gt;&#10;&lt;p&gt;浏览流程&lt;br&gt;&#10;调用朋友圈CGI&lt;br&gt;&#10;拉取时间线&lt;br&gt;&#10;拉取新发表元数据&lt;br&gt;&#10;拉取CDN上的图片&lt;/p&gt;&#10;&lt;p&gt;数据单副本、索引写扩散、检查更新单读取&lt;br&gt;&#10;数据（发表）单副本：减少内存开销&lt;br&gt;&#10;索引写扩散、检查更新单读取：减少检查更新时的读扩散&lt;br&gt;&#10;写比较慢，失败可以重试；读不可等待&lt;/p&gt;&#10;&lt;p&gt;赞、评论与浏览&lt;br&gt;&#10;往赞、评论表插入发表索引和对应赞、评论&lt;/p&gt;&#10;&lt;p&gt;微信部署、接入与容灾&lt;br&gt;&#10;1地3园区对等部署，对等接入（电信、移动、联通）；数据对等分布于同步；对等服务&lt;br&gt;&#10;容灾，任何两个园区都可以提供全量无损服务&lt;br&gt;&#10;数据中心分布：上海、深圳、香港、加拿大&lt;br&gt;&#10;通信优先专线服务；其次公网（加密）&lt;br&gt;&#10;各数据中心可独立提供服务&lt;br&gt;&#10;各数据中心通过idc queue异步同步写入（自动重试）&lt;/p&gt;&#10;&lt;p&gt;核心数据读写分析&lt;br&gt;&#10;相册与发表&lt;br&gt;&#10;本地idc写入，单向同步到其他idc&lt;br&gt;&#10;key的全局唯一性保证无冲突（根据idc预先生成）&lt;br&gt;&#10;时间线&lt;br&gt;&#10;本地idc只保存本地用户时间线的key，无需同步&lt;/p&gt;&#10;&lt;p&gt;跨洋同步的挑战和应对&lt;br&gt;&#10;挑战：大带宽延迟、丢包、乱序、低可靠性（专心中断）&lt;br&gt;&#10;应对：延迟、丢包、乱序达到一定程度自动从tcp切换到udp；专线中断自动切换到公网（AES加密）&lt;/p&gt;&#10;&lt;p&gt;评论、赞写冲突&lt;br&gt;&#10;因果一致性（不同数据中心保证key不重复，比如不同idc取模）&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/presentations/design-and-implementation-of-distributed-monitoring-system" target="_blank" rel="noopener"&#10; &gt;分布式监控系统的设计与实现&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/presentations/technology-of-weixin-moments" target="_blank" rel="noopener"&#10; &gt;微信朋友圈技术之道&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>MySql 慢日志分析</title><link>https://courages.us/mysql-%E6%85%A2%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90/</link><pubDate>Mon, 05 Oct 2015 14:27:50 +0800</pubDate><guid>https://courages.us/mysql-%E6%85%A2%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90/</guid><description>&lt;p&gt;最近老是碰上MySql报错：1203:User already has more than ‘max_user_connections’ active，之前都没出现过，感觉应该是慢查询导致的。向运维拷贝慢日志分析，慢日志开、启配置参考&lt;a class="link" href="http://my.oschina.net/moooofly/blog/160201" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;拷贝出来的日志很大，需要按故障时间点做一下切割，以便缩小排查范围。按照&lt;a class="link" href="https://github.com/wubx/mysql-binlog-statistic/blob/master/bin/cutlogbytime" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;提供的cutlogbytime.pl脚本运行却报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./cutlogbytime.pl slow.log &lt;span style="color:#ae81ff"&gt;1443103200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1443117600&lt;/span&gt; &amp;gt; yestoday.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 1:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 4:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./cutlogbytime.pl: line 5: use: command not found&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 5:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./cutlogbytime.pl: line 6: use: command not found&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 6:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;: command not foundline 7:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/cutlogbytime.pl: line 8: syntax error near unexpected token `{&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;/cutlogbytime.pl: line 8: &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;@ARGV&amp;lt;2&lt;span style="color:#f92672"&gt;){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;去掉顶行的空格后再运行，还是报错&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./cutlogbytime.pl slow.log &lt;span style="color:#ae81ff"&gt;1443103200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1443117600&lt;/span&gt; &amp;gt; today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-bash: ./cutlogbytime.pl: /usr/bin/perl^M: bad interpreter: No such file or directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后参考&lt;a class="link" href="http://stackoverflow.com/questions/2517106/why-do-i-get-use-command-not-found-when-i-run-my-perl-script" target="_blank" rel="noopener"&#10; &gt;stackoverflow上面的答案&lt;/a&gt;更改运行方式为Perl（而不是shell），就可以了。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl cutlogbytime.pl slow.log &lt;span style="color:#ae81ff"&gt;1443103200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1443117600&lt;/span&gt; &amp;gt; today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用mysqlslowdump（perl脚本）来分析日志，-s参数表示排序方式：r表示影响行数（Rows），t表示耗时（Time），c表示查询次数（Count）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@entos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl mysqldumpslow.pl -s r -t &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Reading mysql slow query log from today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; Time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;190.48s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;190s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Lock&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.00s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Rows&lt;span style="color:#f92672"&gt;=&lt;/span&gt;21829854.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;21829854&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, xx&lt;span style="color:#f92672"&gt;[&lt;/span&gt;xxxx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;@&lt;span style="color:#f92672"&gt;[&lt;/span&gt;192.168.10.139&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SELECT /*!N SQL_NO_CACHE */ * FROM &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;errormessage&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count: &lt;span style="color:#ae81ff"&gt;32791&lt;/span&gt; Time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;40.95s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1342865s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Lock&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.05s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1512s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Rows&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;32791&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, xx&lt;span style="color:#f92672"&gt;[&lt;/span&gt;xxxx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;@10hosts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; * from connectinfo where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N ORDER BY CreateDatetime DESC LIMIT N&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; Time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;3.71s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;11s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Lock&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.02s &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Rows&lt;span style="color:#f92672"&gt;=&lt;/span&gt;300.0 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;900&lt;span style="color:#f92672"&gt;)&lt;/span&gt;, xx&lt;span style="color:#f92672"&gt;[&lt;/span&gt;xxxx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;@2hosts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; SeverName from errormessage where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt; and ServerType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N and level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N and MsgType &amp;lt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt; N&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个语句返回行数21829854，查看具体慢日志，之后需要插入这张表的进程均处于等待状态。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Time: 150924 1:03:12&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.139] Id: 1493761&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 190.479062 Lock_time: 0.000000 Rows_sent: 21829854 Rows_examined: 21829854&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027792;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SELECT /*!40001 SQL_NO_CACHE */ * FROM `errormessage`;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Time: 150924 1:03:14&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.168] Id: 1498010&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 59.669817 Lock_time: 57.159403 Rows_sent: 0 Rows_examined: 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027794;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;insert into errormessage (`ID`,`ServerType`,`MsgType`,`Level`,`dev`,`content`,`EventTime`,`SeverName`) values ( &amp;#39;1217&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;4&amp;#39;, &amp;#39;4&amp;#39;, &amp;#39;827&amp;#39;, &amp;#39;erc:start erc error,songid=46243,keymd5=ee1275b26762e85a7f00e9890bdc092e,ercmd5=abbc3ea9102dbd003b7aa0547dcbf6fa&amp;#39;, &amp;#39;2015-09-23 21:49:27&amp;#39;, &amp;#39;192.168.15.117&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.205] Id: 1494756&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 157.211158 Lock_time: 154.673647 Rows_sent: 0 Rows_examined: 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027794;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;insert into errormessage (`ID`,`ServerType`,`MsgType`,`Level`,`dev`,`content`,`EventTime`,`SeverName`) values ( &amp;#39;865&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;1&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;106&amp;#39;, &amp;#39;检测正常！&amp;#39;, &amp;#39;2015-09-24 01:01:18&amp;#39;, &amp;#39;192.168.0.33&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# User@Host: xx[xxxx] @ [192.168.10.213] Id: 1496479&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Query_time: 100.733230 Lock_time: 98.210902 Rows_sent: 0 Rows_examined: 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp=1443027794;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;insert into errormessage (`ID`,`ServerType`,`MsgType`,`Level`,`dev`,`content`,`EventTime`,`SeverName`) values ( &amp;#39;2472&amp;#39;, &amp;#39;3&amp;#39;, &amp;#39;2&amp;#39;, &amp;#39;4&amp;#39;, &amp;#39;809&amp;#39;, &amp;#39;videoseripnoconfig&amp;#39;, &amp;#39;2015-09-24 01:02:26&amp;#39;, &amp;#39;192.168.0.18&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分析这几天的日志，发现故障时间点附近都是这个语句引起后面的SQL堵塞。原来是每天早上1点开始备份并同步全表数据，锁住了这个表导致后面的所有这个表的insert操作处于等待状态。mysqldump应该使用&lt;a class="link" href="http://dba.stackexchange.com/questions/71961/mysqldump-single-transaction-yet-update-queries-are-waiting-for-the-backup" target="_blank" rel="noopener"&#10; &gt;–single-transaction来避免锁表&lt;/a&gt;，类似下面&lt;a class="link" href="http://tencentdba.com/blog/mysqldump-backup-principle/" target="_blank" rel="noopener"&#10; &gt;这个&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysqldump –uuser -p --skip-opt -q -R --single-transaction --default-character-set&lt;span style="color:#f92672"&gt;=&lt;/span&gt;utf8 --master-data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; --create-option --no-autocommit –S &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;sock&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; -B &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DBName&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &amp;gt; backup.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是这样仍然是全表扫描进行备份，如果能够增量备份的话，影响要小很多，或者数据做冷热/新旧之分，定期将新（每天）/热数据转入旧（历史）/冷数据中。后面运维的解决方案是：升级数据库机器从虚拟机变为实体机，配置从机，并从从机进行备份同步。&lt;/p&gt;&#10;&lt;p&gt;上面mysqlslowdump使用影响行数来排序，事实上用另外两个类型（时间，次数）分析结果是connectinfo比较频繁，一直以来都认为是这个表的操作引起的。这里还尝试了其他工具来分析，使用&lt;a class="link" href="https://github.com/daniel-nichter/hackmysql.com/tree/master/mysqlsla" target="_blank" rel="noopener"&#10; &gt;mysqlsla.pl&lt;/a&gt;进行分析，相关参数选项参考&lt;a class="link" href="https://code.google.com/p/memcache-top/issues/detail?id=12" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl mysqlsla.pl today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Auto-detected logs as slow logs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Report &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; slow logs: today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;60.57k queries total, &lt;span style="color:#ae81ff"&gt;17&lt;/span&gt; unique&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Sorted by &lt;span style="color:#e6db74"&gt;&amp;#39;t_sum&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Grand Totals: Time 5.38M s, Lock 3.22M s, Rows sent 21.86M, Rows Examined 184.46M&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;______________________________________________________________________ &lt;span style="color:#ae81ff"&gt;001&lt;/span&gt; ___&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count : 25.59k &lt;span style="color:#f92672"&gt;(&lt;/span&gt;42.24%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time : 3905525.574451 s total, 152.643069 s avg, 113.07488 s to 2720.338946 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;72.64%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Time : 3260112.482495 s total, 134.12789 s avg, 113.07488 s to 282.366041 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Lock Time &lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : 3168076.975558 s total, 123.820721 s avg, 108.548105 s to 311.639359 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;98.45%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Lock : 2961933.212121 s total, 121.860167 s avg, 108.548105 s to 123.487106 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows sent : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.00%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows examined : &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to 4.92k max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.75%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Users :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.147 : 10.65% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2724&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.26% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6215&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.209 : 10.33% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2643&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6156&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.205 : 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2599&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6036&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.211 : 10.13% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2591&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.98% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6042&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.207 : 9.93% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2541&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6024&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.161 : 9.83% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2515&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5960&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.149 : 9.81% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2510&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6028&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.215 : 9.76% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2498&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.85% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5963&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.168 : 9.71% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2485&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5868&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.213 : 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;2480&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.66% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5851&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query abstract:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N; UPDATE connectinfo SET devicetag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, connectipaddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, updatedatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; WHERE ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N AND apptype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query sample:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1443027797;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;update connectinfo set DeviceTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;1070A416AF000000&amp;#39;&lt;/span&gt;, ConnectIPAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;60.174.116.165&amp;#39;&lt;/span&gt;, UpdateDatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5358&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;______________________________________________________________________ &lt;span style="color:#ae81ff"&gt;002&lt;/span&gt; ___&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count : 32.79k &lt;span style="color:#f92672"&gt;(&lt;/span&gt;54.14%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time : 1344378.871914 s total, 40.99841 s avg, 2.000747 s to 1944.548192 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;25.01%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Time : 587407.556704 s total, 18.85678 s avg, 2.000747 s to 233.465042 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Lock Time &lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : 1512.917798 s total, 46.138 ms avg, &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt; ▒s to 114.302 ms max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.05%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Lock : 1414.978902 s total, 45.423 ms avg, &lt;span style="color:#ae81ff"&gt;76&lt;/span&gt; ▒s to 50.514 ms max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows sent : &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.15%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows examined : 4.92k avg, 4.92k to 4.92k max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;87.41%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Users :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.209 : 10.24% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3359&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6156&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.149 : 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3331&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6028&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.147 : 10.11% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3315&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.26% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6215&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.211 : 10.03% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3288&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.98% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6042&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.207 : 10.02% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3285&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6024&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.161 : 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3268&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5960&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.215 : 9.96% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3266&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.85% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5963&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.205 : 9.92% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3254&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6036&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.168 : 9.86% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3234&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5868&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.213 : 9.73% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;3191&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.66% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5851&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query abstract:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N; SELECT * FROM connectinfo WHERE ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N AND apptype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N ORDER BY createdatetime DESC LIMIT N;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query sample:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1443027795;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; * from connectinfo where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7646&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ORDER BY CreateDatetime DESC LIMIT 1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;______________________________________________________________________ &lt;span style="color:#ae81ff"&gt;003&lt;/span&gt; ___&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Count : &lt;span style="color:#ae81ff"&gt;842&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.39%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time : 66663.314786 s total, 79.172583 s avg, 2.011408 s to 673.604537 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.24%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Time : 56684.989954 s total, 70.944919 s avg, 2.011408 s to 193.623235 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Lock Time &lt;span style="color:#f92672"&gt;(&lt;/span&gt;s&lt;span style="color:#f92672"&gt;)&lt;/span&gt; : 48221.988255 s total, 57.27077 s avg, &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; ▒s to 185.402303 s max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;1.50%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 95% of Lock : 40627.196184 s total, 50.847555 s avg, &lt;span style="color:#ae81ff"&gt;69&lt;/span&gt; ▒s to 166.67704 s max&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows sent : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.00%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Rows examined : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; avg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; to &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; max &lt;span style="color:#f92672"&gt;(&lt;/span&gt;0.00%&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Database :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Users :&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.207 : 11.64% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;98&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6024&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.205 : 11.28% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;95&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.97% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6036&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.213 : 10.93% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;92&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.66% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5851&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.161 : 10.45% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;88&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5960&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.149 : 10.33% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;87&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.95% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6028&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.211 : 9.74% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;82&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.98% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6042&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.147 : 9.38% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.26% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6215&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.215 : 9.38% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;79&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.85% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5963&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.168 : 9.03% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;76&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 9.69% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;5868&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xx@ 192.168.10.209 : 7.84% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;66&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of query, 10.16% &lt;span style="color:#f92672"&gt;(&lt;/span&gt;6156&lt;span style="color:#f92672"&gt;)&lt;/span&gt; of all users&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Query abstract:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SET timestamp&lt;span style="color:#f92672"&gt;=&lt;/span&gt;N; INSERT INTO errormessage &lt;span style="color:#f92672"&gt;(&lt;/span&gt;id,servertype,msgtype,level,dev,content,eventtime,severname&lt;span style="color:#f92672"&gt;)&lt;/span&gt; VALUES &lt;span style="color:#f92672"&gt;(&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用mysqlsla可以看SQL语句的执行数量/比例，影响行数，用户，占比等。，从这里看很可能认为是connectinfo表（95%以上）引起，SHOW PROCESSLIST也是如此 。&lt;br&gt;&#10;由于这个文件我是单独下载回来的，运行mysqlsla.pl时候碰到很多错误，逐个安装解决了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl mysqlsla.pl today.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Can&lt;span style="color:#e6db74"&gt;&amp;#39;t locate Time/HiRes.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at mysqlsla.pl line 2092.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;BEGIN failed--compilation aborted at mysqlsla.pl line 2092.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;#解决方法&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[vagrant@centos64 mysql-log-filter-1.9]$ sudo yum install perl-Time-HiRes&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[vagrant@centos64 mysql-log-filter-1.9]$ perl -MCPAN -e &amp;#39;&lt;/span&gt;install DBI&lt;span style="color:#e6db74"&gt;&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Can&amp;#39;&lt;/span&gt;t locate CPAN.pm in @INC &lt;span style="color:#f92672"&gt;(&lt;/span&gt;@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .&lt;span style="color:#f92672"&gt;)&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BEGIN failed--compilation aborted.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#解决方法&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 mysql-log-filter-1.9&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ sudo yum install perl-DBI&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正确的方法是应该检测对应根目录下面的Makefile.PL，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@centos64 percona-toolkit-2.2.15&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ perl Makefile.PL&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#如果报以下错误，需要先安装对应模块，简单点就是&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#sudo yum install perl-devel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Can&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t locate ExtUtils/MakeMaker.pm in @INC &lt;span style="color:#f92672"&gt;(&lt;/span&gt;@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .&lt;span style="color:#f92672"&gt;)&lt;/span&gt; at Makefile.PL line 1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BEGIN failed--compilation aborted at Makefile.PL line 1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装对应模块，参考&lt;a class="link" href="http://modperlbook.org/html/3-9-1-Installing-Perl-Modules-into-a-Nonstandard-Directory.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;br&gt;&#10;使用Percona公司的工具&lt;a class="link" href="https://www.percona.com/doc/percona-toolkit/2.2/pt-query-digest.html" target="_blank" rel="noopener"&#10; &gt;pt-query-diges&lt;/a&gt;t来分析也得到了同mysqlsla类似的结果&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 bin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ pt-query-digest ../../today4.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 9.8s user time, 700ms system time, 21.05M rss, 73.66M vsz&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Current date: Mon Oct 5 05:52:01 2015&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Hostname: vagrant-centos64.vagrantup.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Files: ../../today.log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Overall: 60.57k total, 17 unique, 4.54 QPS, 402.68x concurrency ________&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Time range: 2015-09-23 22:17:29 to 2015-09-24 02:00:00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Attribute total min max avg 95% stddev median&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ============ ======= ======= ======= ======= ======= ======= =======&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Exec time 5376198s 2s 2720s 89s 258s 118s 57s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Lock time 3217840s 0 312s 53s 118s 60s 48ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows sent 20.85M 0 20.82M 361.00 0.99 84.46k 0.99&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows examine 175.91M 0 20.82M 2.97k 4.71k 84.48k 4.71k&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query size 7.85M 64 597 135.90 151.03 27.56 112.70&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Profile&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rank Query ID Response time Calls R/Call V/M Item&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ==== ================== ================== ===== ======== ===== ========&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1 0xF1132168DB0BFC57 3905525.5745 72.6% 25586 152.6431 61.61 UPDATE connectinfo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2 0xD4B317E755A0ABD7 1344378.8719 25.0% 32791 40.9984 30... SELECT connectinfo&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 3 0xE23849EE6FB19DAE 66663.3148 1.2% 842 79.1726 62.99 INSERT errormessage&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query 1: 7.52 QPS, 1.15kx concurrency, ID 0xF1132168DB0BFC57 at byte 16243195&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# This item is included in the report because it matches --limit.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Scores: V/M = 61.61&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Time range: 2015-09-24 01:03:17 to 02:00:00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Attribute pct total min max avg 95% stddev median&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ============ === ======= ======= ======= ======= ======= ======= =======&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Count 42 25586&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Exec time 72 3905526s 113s 2720s 153s 271s 97s 124s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Lock time 98 3168077s 109s 312s 124s 118s 14s 118s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows sent 0 0 0 0 0 0 0 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Rows examine 0 1.33M 0 4.80k 54.39 0 504.65 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query size 48 3.78M 149 157 154.94 151.03 0.52 151.03&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# String:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Hosts 192.168.10.147 (2724/10%)... 9 more&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Users gate&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Query_time distribution&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1us&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 10us&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 100us&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 10ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 100ms&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 10s+ ################################################################&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Tables&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# SHOW TABLE STATUS LIKE &amp;#39;connectinfo&amp;#39;\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# SHOW CREATE TABLE `connectinfo`\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;update connectinfo set DeviceTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;10705BDDCD000000&amp;#39;&lt;/span&gt;, ConnectIPAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;115.231.63.78&amp;#39;&lt;/span&gt;, UpdateDatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6912&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0&lt;span style="color:#ae81ff"&gt;\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Converted for EXPLAIN&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# EXPLAIN /*!50100 PARTITIONS*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; DeviceTag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;10705BDDCD000000&amp;#39;&lt;/span&gt;, ConnectIPAddress&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;115.231.63.78&amp;#39;&lt;/span&gt;, UpdateDatetime&lt;span style="color:#f92672"&gt;=&lt;/span&gt;now&lt;span style="color:#f92672"&gt;()&lt;/span&gt; from connectinfo where ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6912&lt;/span&gt; and AppType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0&lt;span style="color:#ae81ff"&gt;\G&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PS：这个问题解决后没几天，数据库又出问题，以为又是慢SQL什么的，结果是交换机网口问题。。。数据传输太慢，导致主从不同步。。。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://hzcsky.blog.51cto.com/1560073/479991" target="_blank" rel="noopener"&#10; &gt;mysql 慢日志分析&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bbs.chinaunix.net/thread-4076473-1-1.html" target="_blank" rel="noopener"&#10; &gt;慢日志按时间截取&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://my.oschina.net/moooofly/blog/160201" target="_blank" rel="noopener"&#10; &gt;MySQL 之 slow log&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/zhanjindong/p/3472804.html" target="_blank" rel="noopener"&#10; &gt;MySQL优化—工欲善其事，必先利其器（2）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.wllog.net/2014/09/02/744.html" target="_blank" rel="noopener"&#10; &gt;日志常用统计技巧&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://sunheran.com/2015/03/12/mysql-sql-performance/" target="_blank" rel="noopener"&#10; &gt;性能优化之MySQL优化（一）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/wyzxg/article/details/7268969" target="_blank" rel="noopener"&#10; &gt;mysqlsla的安装与使用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://cocos.iteye.com/blog/1122836" target="_blank" rel="noopener"&#10; &gt;安装DBI组件。 Can’t locate DBI.pm in @INC-mysql接口&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.google.com/p/memcache-top/issues/detail?id=12" target="_blank" rel="noopener"&#10; &gt;Issue 12: Can’t locate Time/HiRes.pm&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ccvita.com/326.html" target="_blank" rel="noopener"&#10; &gt;打开MySQL的慢查询记录&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://perl%20Makefile.PL" target="_blank" rel="noopener"&#10; &gt;“Can’t locate ExtUtils/MakeMaker.pm” while compile git&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.olindata.com/blog/2014/08/analysing-slow-mysql-queries-pt-query-digest" target="_blank" rel="noopener"&#10; &gt;analysing slow MySQL queries with pt-query-digest&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tencentdba.com/blog/mysqldump-backup-principle/" target="_blank" rel="noopener"&#10; &gt;mysqldump备份原理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dba.stackexchange.com/questions/71961/mysqldump-single-transaction-yet-update-queries-are-waiting-for-the-backup" target="_blank" rel="noopener"&#10; &gt;mysqldump –single-transaction, yet update queries are waiting for the backup&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.51yip.com/mysql/1042.html" target="_blank" rel="noopener"&#10; &gt;mysql 利用binlog增量备份，还原实例&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bbs.chinaunix.net/thread-1017116-1-1.html" target="_blank" rel="noopener"&#10; &gt;MySQl备份恢复策略（完全+增量备份策略）&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 处理行结束符</title><link>https://courages.us/php-%E5%A4%84%E7%90%86%E8%A1%8C%E7%BB%93%E6%9D%9F%E7%AC%A6/</link><pubDate>Mon, 31 Aug 2015 13:02:11 +0800</pubDate><guid>https://courages.us/php-%E5%A4%84%E7%90%86%E8%A1%8C%E7%BB%93%E6%9D%9F%E7%AC%A6/</guid><description>&lt;p&gt;我们平台有个功能支持导入一行一个编号的文本，进行批量处理，类似CSV文件，代码是这样的：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$arrLine &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file&lt;/span&gt;($strFilePath);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt;($arrLine &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $k &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $v){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一直用都用的好好的，今天有同事导入却不正常了。用记事本打开要导入的文件来看，发现文件里面的内容都是只有一行；用EditPlus打开来看却又是正常的，不过显示是Mac平台的文件，猜测应该是换行符不一样导致的。Google了一下，发现果然如此，不同操作系统的行结束符是不一样的：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Windows\DOS：\r\n &amp;lt;\li&amp;gt;&lt;/li&gt;&#10;&lt;li&gt;Unix\Linux：\n &amp;lt;\li&amp;gt;&lt;/li&gt;&#10;&lt;li&gt;Macintosh：\r &amp;lt;\li&amp;gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;另外，TCP/IP协议传输文本结束符也是\r\n。PHP的文件系统函数file和fgets默认不检测行结束符，所以不能正确处理。可以将这些换行符处理成其他的，再来断行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strFileContent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str_replace&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/r/n&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/r&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/n&amp;#34;&lt;/span&gt;), &lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;, $strFileContent); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$arrLine &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;explode&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;,&amp;#39;&lt;/span&gt; , $strFileContent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP官网也提供了相应的解决方法，更改php.ini配置，或者ini_set(‘auto_detect_line_endings’, ‘On’)即可。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;Note: 在读取在 Macintosh 电脑中或由其创建的文件时， 如果 PHP 不能正确的识别行结束符，启用运行时配置可选项 auto_detect_line_endings 也许可以解决此问题。&lt;/p&gt;&#10;&lt;p&gt;auto_detect_line_endings boolean&lt;br&gt;&#10;当设为 On 时，PHP 将检查通过 fgets() 和 file() 取得的数据中的行结束符号是符合 Unix，MS-DOS，还是 Macintosh 的习惯。&lt;/p&gt;&#10;&lt;p&gt;这使得 PHP 可以和 Macintosh 系统交互操作，但是默认值是 Off，因为在检测第一行的 EOL 习惯时会有很小的性能损失，而且在 Unix 系统下使用回车符号作为项目分隔符的人们会遭遇向下不兼容的行为。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;PHP从4.3开始使用常量PHP_EOL来代替不同平台的换行符，在代码中也应该使用PHP_EOL而不是写\r\n，否则会造成不必要的平台环境问题。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/1761051/difference-between-n-and-r" target="_blank" rel="noopener"&#10; &gt;Difference between \n and \r?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/16523734/what-is-the-difference-between-windows-csv-and-mac-csv" target="_blank" rel="noopener"&#10; &gt;what is the difference between windows csv and mac csv?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/function.file.php" target="_blank" rel="noopener"&#10; &gt;PHP Fucntion file&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/filesystem.configuration.php#ini.auto-detect-line-endings" target="_blank" rel="noopener"&#10; &gt;PHP auto-detect-line-endings&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/128560/when-do-i-use-the-php-constant-php-eol" target="_blank" rel="noopener"&#10; &gt;When do I use the PHP constant “PHP_EOL”?&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Git及GitHub 使用</title><link>https://courages.us/git%E5%8F%8Agithub-%E4%BD%BF%E7%94%A8/</link><pubDate>Sun, 30 Aug 2015 16:46:59 +0800</pubDate><guid>https://courages.us/git%E5%8F%8Agithub-%E4%BD%BF%E7%94%A8/</guid><description>&lt;p&gt;在前面的文章里面，经常会看到使用&lt;a class="link" href="https://git-scm.com/" target="_blank" rel="noopener"&#10; &gt;Git&lt;/a&gt;来下载代码，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git clone https://github.com/zeromq/zeromq4-x.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Git 是有Linux开发者Linus Torvalds开发的分布式版本控制软件，最初用于Linux内核代码管理，它不需要服务器端软件，就可以进行版本控制，使得离线/本地开发非常方便。与SVN不同，Git基本在本机工作（就像在本机也搭建了一个SVN服务器），具有以下优点：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;可以向本地提交代码，当服务器不可用时，仍然可以离线提交代码&lt;/li&gt;&#10;&lt;li&gt;可以向本地提交代码，在本地功能开发完成后，再向服务器提交有用的变更，项目代码不会有频繁变更&lt;/li&gt;&#10;&lt;li&gt;分布式存储，每个开发者均有一份代码，不用担心服务器上的代码丢失&lt;/li&gt;&#10;&lt;li&gt;支持Pull Request，功能完成后通知其他成员进行代码审查&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Git提倡使用主干作为稳定可发布的代码，使用分支进行开发，与我们的软件管理思路大致一致：分支开发，分支测试，分支/主干发布。多人协作项目，需要有良好的分支开发意识，以免在主干上互相冲突和影响软件稳定。&lt;br&gt;&#10;通过MINGW32安装&lt;a class="link" href="https://git-scm.com/download/win" target="_blank" rel="noopener"&#10; &gt;Git&lt;/a&gt;，在Windows下面也可以使用Git。它提供了在右键菜单里面集成了Git管理的一些操作，也提供了Bash进行交互。Git常用操作包括：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取帮助&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git --help&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取某个git命令的帮助信息，使用默认浏览器查看&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git help branch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 初始化当前目录作为git仓库&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git init&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 复制一个远程仓库到本地&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git clone &amp;lt;url&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 切换到主分支master（默认）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 设置个人账号信息，提交代码时会同时提交这些信息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git config --global user.name &lt;span style="color:#e6db74"&gt;&amp;#34;mystery&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git config --global user.email mystery@example.com:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 提交全部代码变更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add --all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 仅提交boot.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add boot.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 仅提交路径generator/lib&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add generator/lib&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 仅提交路径generator/lib&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git add generator/lib&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 删除文件 test.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git rm test.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 移动文件 test.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git mvtest.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看当前代码是否有未提交的变更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git status&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 比较代码差异&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git diff&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 确认提交代码并备注&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git commit -m &lt;span style="color:#e6db74"&gt;&amp;#39;test comment &amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 自动提交所有文件变更，不需要上面的步骤了&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git commit -a -m &lt;span style="color:#e6db74"&gt;&amp;#39;added new comments&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看提交历史记录&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看历史记录前2条，并显示变更&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git log -p -2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 撤销上一次commit修改&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git reset HEAD&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 与远程仓库库同步&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git fetch origin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git rebase origin/master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 多个本地合并commit合并成一个&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git rebase -i origin/master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 推送本地更新到远程仓库&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git push --force origin feature-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在master分支上创建分支develop，-b则表示创建分支并切换到该分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout -b develop master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在develop分支上创建feature-x分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout -b feature-x develop&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 列出所有分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git branch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建master分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git branch master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 删除分支feature-x&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git branch -d feature-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在mater上面合并feature-x分支代码&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git checkout master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git merge feature-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 合并远程仓库代码到本地&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git pull origin master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git fetch origin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git merge --no-ff origin/master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 查看当前镜像&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git tag&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 为当前仓库创建一个镜像标签&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ git tag -a v1.0 -m &lt;span style="color:#e6db74"&gt;&amp;#39;publish &amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在已有项目目录上使用git&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git init .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git remote add origin &amp;lt;repository-url&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git pull origin master&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git add .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git commit -am &lt;span style="color:#e6db74"&gt;&amp;#34;commit message&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push　origin master&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Git还提供了一个工具，可以将svn仓库代码导入git仓库，参考&lt;a class="link" href="http://gitbook.liuhui998.com/6_4.html" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://github.com/" target="_blank" rel="noopener"&#10; &gt;GitHub&lt;/a&gt;是一个著名的在线代码托管/分享/交流网站，提供免费的代码托管服务，支持分布式版本控制软件Git管理的工程代码，方便交流和协作。在这里可以找到各种各样的开源软件代码，比如&lt;a class="link" href="https://github.com/php/php-src" target="_blank" rel="noopener"&#10; &gt;PHP-SRC&lt;/a&gt;，对于程序员的帮助也是显而易见的，反之从一个程序员关注的项目也可以看出一个人的开发方向和水平。&lt;/p&gt;&#10;&lt;p&gt;GitHub开发了一个&lt;a class="link" href="https://desktop.github.com/" target="_blank" rel="noopener"&#10; &gt;客户端&lt;/a&gt;用于与GitHub网站进行交互，隐藏了一些操作的细节，相比SVN要大气，方便一些。但是在线安装的方式对于国内并不方面。。&lt;br&gt;&#10;通过GitHub客户端可以直接创建、管理GitHub线上托管的代码。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/08/git-1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="git-1" class="gallery-image" data-flex-basis="416px" data-flex-grow="173" height="173" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/08/git-1-300x173.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/08/git-2.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="git-2" class="gallery-image" data-flex-basis="375px" data-flex-grow="156" height="192" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/08/git-2-300x192.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;与TortoiseSVN类似，也有&lt;a class="link" href="https://github.com/TortoiseGit/TortoiseGit" target="_blank" rel="noopener"&#10; &gt;TortoiseGit&lt;/a&gt;用于Windows下面的Git管理。&lt;br&gt;&#10;作公司内部的代码管理，可以使用&lt;a class="link" href="https://about.gitlab.com/" target="_blank" rel="noopener"&#10; &gt;GitLab&lt;/a&gt;来搭建私有的代码托管服务器，参考&lt;a class="link" href="https://phphub.org/topics/576" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.ruanyifeng.com/blog/2015/08/git-use-process.html" target="_blank" rel="noopener"&#10; &gt;Git 使用规范流程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/NeuOL/neuola-legacy/wiki/github%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97" target="_blank" rel="noopener"&#10; &gt;Github使用指南&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://git.oschina.net/progit/" target="_blank" rel="noopener"&#10; &gt;Pro Git（中文版）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ibm.com/developerworks/cn/linux/l-git/" target="_blank" rel="noopener"&#10; &gt;使用 Git 管理源代码&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/xirong/my-git/blob/master/git-workflow-tutorial.md" target="_blank" rel="noopener"&#10; &gt;Git工作流程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.runoob.com/git/git-branch.html" target="_blank" rel="noopener"&#10; &gt;Git 分支管理&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.oschina.net/translate/a-successful-git-branching-model" target="_blank" rel="noopener"&#10; &gt;介绍一个成功的 Git 分支模型&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://gitbook.liuhui998.com/6_4.html" target="_blank" rel="noopener"&#10; &gt;从其他代码管理工具迁移到Git&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ruanyifeng.com/blog/2012/07/git.html" target="_blank" rel="noopener"&#10; &gt;Git分支管理策略&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://phphub.org/topics/576" target="_blank" rel="noopener"&#10; &gt;[Sever Hacks] 搭建私有 GitLab 代码托管服务器&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP C扩展框架Phalcon</title><link>https://courages.us/php-%E6%A1%86%E6%9E%B6phalcon/</link><pubDate>Thu, 30 Jul 2015 13:33:59 +0800</pubDate><guid>https://courages.us/php-%E6%A1%86%E6%9E%B6phalcon/</guid><description>&lt;p&gt;&lt;a class="link" href="https://phalconphp.com/zh/" target="_blank" rel="noopener"&#10; &gt;Phalcon&lt;/a&gt;是一个C语言写的高性能PHP框架，相比PHP写的框架，它作为PHP的扩展在进程开启时便加载了，节省了每一次请求时的类库加载、MVC框架分派的开销。前面提到的使用&lt;a class="link" href="https://courages.us/php-%e6%89%a9%e5%b1%95%e5%bc%80%e5%8f%91%e4%b9%8bzephir/" target="_blank" rel="noopener"&#10; &gt;Zephir&lt;/a&gt;来开发PHP扩展也是这个项目贡献的。&lt;br&gt;&#10;在CentOS 上安装Phalcon，因为之前安装过zephire了，所以直接下载cphalcon来编译安装就可以了，可以参照&lt;a class="link" href="https://docs.phalconphp.com/en/latest/reference/install.html#linux-solaris" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;安装所需其他lib&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone --depth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; git://github.com/phalcon/cphalcon.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd cphalcon/build/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ./install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.d/phalcon.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建phalcon.ini增加以下内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[phalcon]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=phalcon.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里单独把phalcon.ini单独配置，是因为Phalcon扩展加载要在PDO扩展之后，而我的PDO也是单独配置的。如果不是的话会提示这个错误：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ php -m | grep phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP Warning: PHP Startup: Unable to load dynamic library &lt;span style="color:#e6db74"&gt;&amp;#39;/usr/lib64/php/modules/phalcon.so&amp;#39;&lt;/span&gt; - /usr/lib64/php/modules/phalcon.so: undefined symbol: php_pdo_get_dbh_ce in Unknown on line &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与&lt;a class="link" href="http://framework.zend.com/" target="_blank" rel="noopener"&#10; &gt;Zend Framwork&lt;/a&gt;类似，Phalcon也提供&lt;a class="link" href="https://github.com/phalcon/phalcon-devtools" target="_blank" rel="noopener"&#10; &gt;开发工具&lt;/a&gt;用于快速生成项目骨架&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/phalcon/phalcon-devtools.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd phalcon-devtools&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./phalcon.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ln -s ~/phalcon-devtools/phalcon.php /usr/bin/phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo chmod ugo+x /usr/bin/phalcon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon commands&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，这个开发工具也是需要依赖Phalcon扩展的，否则会提示&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ phalcon command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP Fatal error: Class &lt;span style="color:#e6db74"&gt;&amp;#39;Phalcon\Script&amp;#39;&lt;/span&gt; not found in /home/vagrant/phalcon-devtools/phalcon.php on line &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP Stack trace:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP 1. &lt;span style="color:#f92672"&gt;{&lt;/span&gt;main&lt;span style="color:#f92672"&gt;}()&lt;/span&gt; /home/vagrant/phalcon-devtools/phalcon.php:0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成一个测试项目store&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phalcon scaffold store&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按照官方的Nginx说明配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8005;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name store.localhost;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index index.php index.html index.htm;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set $root_path &amp;#39;/usr/share/nginx/html/tutorial/store/public&amp;#39;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root $root_path;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; try_files $uri $uri/ @rewrite;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location @rewrite {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rewrite ^/(.*)$ /index.php?_url=https://courages.us/$1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location ~ \.php {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_pass unix:/tmp/php5-fpm.sock;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_index /index.php;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include fastcgi.conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_split_path_info ^(.+\.php)(/.+)$;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param PATH_INFO $fastcgi_path_info;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location ~* ^/(css|img|js|flv|swf|download)/(.+)$ {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root $root_path;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location ~ /\.ht {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deny all;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问一下192.168.33.14:8005，提示：Access denied。。。查看Nginx错误日志&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant nginx&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# tail -n 20 error.log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2015/07/28 03:41:42 &lt;span style="color:#f92672"&gt;[&lt;/span&gt;error&lt;span style="color:#f92672"&gt;]&lt;/span&gt; 7343#0: *1 FastCGI sent in stderr: &lt;span style="color:#e6db74"&gt;&amp;#34;Access to the script &amp;#39;/usr/share/nginx/html/tutorial/store/public&amp;#39; has been denied (see security.limit_extensions)&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; reading response header from upstream, client: 192.168.33.1, server: store.localhost, request: &lt;span style="color:#e6db74"&gt;&amp;#34;GET / HTTP/1.1&amp;#34;&lt;/span&gt;, upstream: &lt;span style="color:#e6db74"&gt;&amp;#34;fastcgi://unix:/tmp/php5-fpm.sock:&amp;#34;&lt;/span&gt;, host: &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.14:8005&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一开始还以为是PHP-FPM配置security.limit_extensions引起的，后来发现这个这个参数默认就是注释掉的，没限制。 最后在&lt;a class="link" href="http://askubuntu.com/questions/164627/nginx-php-fpm-access-denied-error" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;找到答案：原来是之前&lt;a class="link" href="https://courages.us/php%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96%e4%b9%8bnginxphp-fpm/" target="_blank" rel="noopener"&#10; &gt;安装Nginx&lt;/a&gt;时配置了：cgi.fix_pathinfo=0，将它改回1（默认值）就可以了。当这个参数为1时，会把 PATH_TRANSLATED 转换为 SCRIPT_FILENAME。当然把这个参数去掉也是可以的&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启Nginx&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service nginx restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与其他PHP框架一样，Phalcon 支持MVC应用开发，提供了诸多组件如，数据库，缓存，队列等。&lt;br&gt;&#10;&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/di.html" target="_blank" rel="noopener"&#10; &gt;Phalcon\DI&lt;/a&gt; 作为全局的服务管理，用于服务注册，比如数据库，缓存，文件等。将这些资源统一起来管理，以便其他地方可以调用，各个需要的地方不再需要是new 一个对象，解除耦合关系。&lt;br&gt;&#10;Phalcon\Events\Manager作为全局的事件管理，用于事件注册，触发，以便自定义消息通知，如数据库查询事件，初始化事件。&lt;br&gt;&#10;Phalcon还有一个比较有特色的地方支持注释解析: Phalcon\Annotations 。&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/annotations.html" target="_blank" rel="noopener"&#10; &gt;官方教程&lt;/a&gt;举例如何使用注释做输出缓存。首先在Dispatcher服务中注册一个监听dispactch事件的缓存插件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$di[&lt;span style="color:#e6db74"&gt;&amp;#39;dispatcher&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $eventsManager &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Phalcon\Events\Manager&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 添加插件到dispatch事件中&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $eventsManager&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;dispatch&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CacheEnablerPlugin&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Phalcon\Mvc\Dispatcher&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setEventsManager&lt;/span&gt;($eventsManager);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $dispatcher;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后实现监听的缓存插件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 为视图启动缓存，如果被执行的action带有@Cache 注释单元。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CacheEnablerPlugin&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Phalcon\Mvc\User\Plugin&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 这个事件在dispatcher中的每个路由被执行前执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;beforeExecuteRoute&lt;/span&gt;($event, $dispatcher)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 解析目前访问的控制的方法的注释&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $annotations &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;annotations&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getMethod&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getActiveController&lt;/span&gt;(),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getActiveMethod&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 检查是否方法中带有注释名称‘Cache’的注释单元&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($annotations&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;has&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Cache&amp;#39;&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 这个方法带有‘Cache’注释单元&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $annotation &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $annotations&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Cache&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 获取注释单元的‘lifetime’参数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $lifetime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $annotation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getNamedParameter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;lifetime&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $options &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;lifetime&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $lifetime);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 检查注释单元中是否有用户定义的‘key’参数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($annotation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hasNamedParameter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $options[&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $annotation&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getNamedParameter&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 为当前dispatcher访问的方法开启cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;view&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cache&lt;/span&gt;($options);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在就可以使用注释来进行缓存了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NewsController&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Phalcon\Mvc\Controller&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;indexAction&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * This is a comment&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Cache(lifetime=86400)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;showAllAction&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;view&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;article&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Articles&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;find&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * This is a comment&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Cache(key=&amp;#34;my-key&amp;#34;, lifetime=86400)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;showAction&lt;/span&gt;($slug)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;view&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;article&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Articles&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;findFirstByTitle&lt;/span&gt;($slug);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为Action增加了缓存，但对Action的代码改动为0（无侵入）并且非常简洁。&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/models-metadata.html#annotations-strategy" target="_blank" rel="noopener"&#10; &gt;数据模型&lt;/a&gt;里面也可以使用注释来对字段进行处理&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Phalcon\Mvc\Model&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Robots&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Model&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Primary&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Identity&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Column(type=&amp;#34;integer&amp;#34;, nullable=false)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Column(type=&amp;#34;string&amp;#34;, length=70, nullable=false)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Column(type=&amp;#34;string&amp;#34;, length=32, nullable=false)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $type;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Column(type=&amp;#34;integer&amp;#34;, nullable=false)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $year;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;路由解析也可以使用RouterAnnotations反射来实现&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @RoutePrefix(&amp;#34;/api/products&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProductsController&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Get(&amp;#34;/&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;indexAction&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Get(&amp;#34;/edit/{id:[0-9]+}&amp;#34;, name=&amp;#34;edit-robot&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;editAction&lt;/span&gt;($id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Route(&amp;#34;/save&amp;#34;, methods={&amp;#34;POST&amp;#34;, &amp;#34;PUT&amp;#34;}, name=&amp;#34;save-robot&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;saveAction&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @Route(&amp;#34;/delete/{id:[0-9]+}&amp;#34;, methods=&amp;#34;DELETE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * conversors={id=&amp;#34;MyConversors::checkId&amp;#34;})&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deleteAction&lt;/span&gt;($id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;infoAction&lt;/span&gt;($id)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;是不是跟&lt;a class="link" href="http://Java%20annotation" target="_blank" rel="noopener"&#10; &gt;Java annotation&lt;/a&gt;有点像？之前介绍的PHPUnit，Zend Framework，还有&lt;a class="link" href="https://symfony.com/" target="_blank" rel="noopener"&#10; &gt;Symfony 2&lt;/a&gt; 和 &lt;a class="link" href="http://www.doctrine-project.org/" target="_blank" rel="noopener"&#10; &gt;Doctrine 2&lt;/a&gt;已经在PHP层面上支持，使用&lt;a class="link" href="http://php.net/manual/zh/reflectionclass.getdoccomment.php" target="_blank" rel="noopener"&#10; &gt;ReflectionClass&lt;/a&gt;便可实现。&lt;br&gt;&#10;Phalcon也支持创&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/cli.html" target="_blank" rel="noopener"&#10; &gt;建命令行应用&lt;/a&gt;，可以将PHP应用打包成Phar，直接运行，也可以结合&lt;a class="link" href="http://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/" target="_blank" rel="noopener"&#10; &gt;命令行颜色&lt;/a&gt;进行输出。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/nginx.html" target="_blank" rel="noopener"&#10; &gt;Nginx 安装说明（Nginx Installation Notes）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://forum.phalconphp.com/discussion/1899/can-t-upgrade-to-phalcon-1-3-0" target="_blank" rel="noopener"&#10; &gt;Can’t upgrade to Phalcon 1.3.0&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://askubuntu.com/questions/164627/nginx-php-fpm-access-denied-error" target="_blank" rel="noopener"&#10; &gt;Nginx/PHP-FPM “Access denied.” error&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/23390531/access-denied-403-for-php-files-with-nginx-php-fpm" target="_blank" rel="noopener"&#10; &gt;Access denied (403) for PHP files with Nginx + PHP-FPM&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://docs.phalconphp.com/zh/latest/reference/tools.html" target="_blank" rel="noopener"&#10; &gt;Phalcon 开发工具（Phalcon Developer Tools）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/15808688/ide-autocomplete-for-phalconphp" target="_blank" rel="noopener"&#10; &gt;IDE autocomplete for PhalconPHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/rdohms/annotations-in-php-they-exist" target="_blank" rel="noopener"&#10; &gt;Annotations in PHP: They Exist&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://theunraveler.com/blog/2012/php-annotations-are-a-horrible-idea/" target="_blank" rel="noopener"&#10; &gt;PHP Annotations Are a Horrible Idea&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/" target="_blank" rel="noopener"&#10; &gt;PHP CLI Colors – PHP Class Command Line Colors (bash)&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用Phar打包发布PHP程序</title><link>https://courages.us/%E4%BD%BF%E7%94%A8phar%E6%89%93%E5%8C%85%E5%8F%91%E5%B8%83php%E7%A8%8B%E5%BA%8F/</link><pubDate>Tue, 21 Jul 2015 11:12:52 +0800</pubDate><guid>https://courages.us/%E4%BD%BF%E7%94%A8phar%E6%89%93%E5%8C%85%E5%8F%91%E5%B8%83php%E7%A8%8B%E5%BA%8F/</guid><description>&lt;p&gt;上一遍&lt;a class="link" href="https://courages.us/php%e6%b5%8b%e8%af%95%e6%a1%86%e6%9e%b6%e5%88%9d%e6%8e%a2%ef%bc%9aphpunit/" target="_blank" rel="noopener"&#10; &gt;介绍PHPUnit&lt;/a&gt;时，下载的PHPUnit是个Phar格式的文件并且可以独立运行。&lt;a class="link" href="http://php.net/manual/zh/intro.phar.php" target="_blank" rel="noopener"&#10; &gt;Phar&lt;/a&gt;归档是PHP 5.3增加的新特性，借鉴了JAVA中的JAR归档，可以将整个目录下的文件打包成单个可执行文件。虽然单个PHP文件也是可执行（Composer的install就是单个PHP文件执行创建对应的Phar），但是显得不方便。&lt;br&gt;&#10;Phar的创建、引用、解压、转换均可以在PHP中完成。要创建Phar需要更改php.ini如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;phar.readonly = On&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phar.readonly = Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;首先在swoole\server目录下创建一个需要打包的文件swoole.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$serv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;swoole_server&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9002&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;worker_num&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//工作进程数量&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;daemonize&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//是否作为守护进程&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;connect&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($serv, $fd){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Client:Connect.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;receive&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($serv, $fd, $from_id, $data) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;($fd, &lt;span style="color:#e6db74"&gt;&amp;#39;Swoole: &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;($fd);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;close&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($serv, $fd) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Client: Close.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$serv&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;start&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在swoole目录下面创建index.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;require&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;server/swoole.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下是否能正常运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 swoole&lt;span style="color:#f92672"&gt;]&lt;/span&gt;php index.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 swoole&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# netstat -apn | grep 9002&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:9002 0.0.0.0:* LISTEN 8436/php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在swoole目录下创建执行打包操作的文件build.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 需要打包的目录&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;swoole.phar&amp;#39;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// 包的名称, 注意它不仅仅是一个文件名, 在stub中也会作为入口前缀&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Phar&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $file, &lt;span style="color:#a6e22e"&gt;FilesystemIterator&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CURRENT_AS_FILEINFO&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;FilesystemIterator&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;KEY_AS_FILENAME&lt;/span&gt;, $file);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 开始打包&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;startBuffering&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;buildFromDirectory&lt;/span&gt;($dir);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;delete&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;build.php&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 设置入口&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setStub&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;?php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Phar::mapPhar(&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$file&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;require &amp;#39;phar://&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$file&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/index.php&amp;#39;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;__HALT_COMPILER();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;?&amp;gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;stopBuffering&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 打包完成&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Finished &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$file&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进行打包&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 swoole&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ php build.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Finished swoole.phar&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试执行一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 swoole&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ php swoole.phar&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant-centos64 swoole&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# netstat -apn | grep 9002&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:9002 0.0.0.0:* LISTEN 8635/php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;到这里swoole.phar可以单独发布执行力。也可以在其他项目（比如WEB）里面引用，例如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;swoole.phar&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//引用里面的文件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//include &amp;#39;phar://swoole.phar/server/swoole.php&amp;#39;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="http://get.jobdeer.com/1213.get" target="_blank" rel="noopener"&#10; &gt;SegmentFault&lt;/a&gt;便是将PHP打包成Phar进行发布的。&lt;br&gt;&#10;打包完成后，也可以将Phar转成Zip格式或解压出来，比如解压PHPUnit&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Phar&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;phpunit.phar&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;convertToExecutable&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Phar&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ZIP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$phar-&amp;gt;extractTo(&amp;#39;phpunit&amp;#39;); &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;刚才我们这样运行的：php swoole.phar，就是还需要在PharP包前面还要加一个php。如果想做成直接可运行的Phar包，可以像单个PHP可执行文件那样在文件开头加上：#!/usr/bin/env php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$phar&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setStub&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;#!/usr/bin/env php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;?php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;Phar::mapPhar(&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$file&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;require &amp;#39;phar://&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$file&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/index.php&amp;#39;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;__HALT_COMPILER();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;?&amp;gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./swoole.phar&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意如果你在window下面编辑刚才段代码的话，可能会报错：-bash: ./swoole.phar: /usr/bin/env: bad interpreter: No such file or directory。解决办法便是更改换行符为Unix格式，参见&lt;a class="link" href="http://-bash:%20./swoole.phar:%20/usr/bin/evn:%20bad%20interpreter:%20No%20such%20file%20or%20directory" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;GitHub上有个项目：&lt;a class="link" href="https://github.com/clue/phar-composer" target="_blank" rel="noopener"&#10; &gt;phar-composer&lt;/a&gt;可以利用&lt;a class="link" href="https://getcomposer.org/" target="_blank" rel="noopener"&#10; &gt;Composer&lt;/a&gt;来打包相应的项目为单个可执行文件。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://segmentfault.com/a/1190000002166235" target="_blank" rel="noopener"&#10; &gt;使用phar上线你的代码包&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://lunae.cc/php-phar-intro" target="_blank" rel="noopener"&#10; &gt;PHP的Phar简介&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://koda.iteye.com/blog/2087021" target="_blank" rel="noopener"&#10; &gt;使用Phar来打包发布PHP程序&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.sitepoint.com/packaging-your-apps-with-phar/" target="_blank" rel="noopener"&#10; &gt;Packaging Your Apps with Phar&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ibm.com/developerworks/cn/opensource/os-php-5.3new4/" target="_blank" rel="noopener"&#10; &gt;PHP V5.3 中的新特性，第 4 部分: 创建并使用 Phar 归档&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.google.com/p/rpmcreate/" target="_blank" rel="noopener"&#10; &gt;rpm打包利器rpm_create简介&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP测试框架初探：PHPUnit</title><link>https://courages.us/php%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E5%88%9D%E6%8E%A2%EF%BC%9Aphpunit/</link><pubDate>Mon, 20 Jul 2015 13:16:03 +0800</pubDate><guid>https://courages.us/php%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E5%88%9D%E6%8E%A2%EF%BC%9Aphpunit/</guid><description>&lt;p&gt;最近开始一个新的项目，涉及到了网络通信的客户/端服务端，刚开始都是边写边调试，完成之后觉得有必要留下相关的测试示例，以便日后使用调试。一些PHP项目会把示例写在文件开头的注释里面，但这样又没办法验证是否能正确运行。&lt;br&gt;&#10;&lt;a class="link" href="http://www.workerman.net/" target="_blank" rel="noopener"&#10; &gt;workerman&lt;/a&gt;是在文件最后留下的运行代码，如RpcClient.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ==以下调用示例==&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;PHP_SAPI&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;cli&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;isset&lt;/span&gt;($argv[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]) &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; $argv[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;basename&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//这里是RpcClient的测试用例&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="https://github.com/sebastianbergmann/phpunit/blob/master/build/phar-autoload.php.in" target="_blank" rel="noopener"&#10; &gt;PHPUnit&lt;/a&gt;则是这样的&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/env php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;realpath&lt;/span&gt;($GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;_SERVER&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;SCRIPT_NAME&amp;#39;&lt;/span&gt;])) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $phar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;realpath&lt;/span&gt;($GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;_SERVER&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;SCRIPT_NAME&amp;#39;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $execute &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $files &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_included_files&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $phar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $files[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $execute &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这有点像python&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;//&lt;/span&gt;这里运行相关调用&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就可以对单个文件的代码边看边测试，但是这会在相关的代码里面混入不必要的测试用例代码，当有依赖于外部文件又不是很方便，于是便想把这部分测例代码独立出来。&lt;br&gt;&#10;&lt;a class="link" href="https://phpunit.de/" target="_blank" rel="noopener"&#10; &gt;PHPUnit&lt;/a&gt;是xUnit测试家族的一员，可以方便对测试代码进行管理，还可以结合其他&lt;a class="link" href="https://phpunit.de/plugins.html" target="_blank" rel="noopener"&#10; &gt;扩展&lt;/a&gt;。依照官网步骤开始：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://phar.phpunit.de/phpunit.phar&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x phpunit.phar&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo mv phpunit.phar /usr/local/bin/phpunit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpunit --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#PHPUnit 4.7.7 by Sebastian Bergmann and contributors.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;写一个测试代码（PHPUnit也可以自动生成对应的测试代码）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Test\Client&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Client\RPC&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RPCTest&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\PHPUnit_Framework_TestCase&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $nMatchID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;567&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;parent&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrAddress &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;tcp://127.0.0.1:9001&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;// 配置服务端列表&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;RPC&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;($arrAddress);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nMatchID&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;567&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;RPC&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;instance&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;\Prize\Service&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;testGet&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$mxRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nMatchID&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;assertTrue&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;is_array&lt;/span&gt;($mxRes));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;assertGreaterThan&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($mxRes));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;testSendGet&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;assertTrue&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send_get&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nMatchID&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#9; * 使用依赖，以便保证在同一个socket链接之内&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#9; * @depends testSendGet&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#9; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;testRecvGet&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$mxRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv_get&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nMatchID&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;assertTrue&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;is_array&lt;/span&gt;($mxRes));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;assertGreaterThan&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($mxRes));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这边的使用了外部类RPC，于是在Bootstrap.php里面定义相关的自动加载规则，以便测试时自动加载&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;STIE_PATH&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;getcwd&lt;/span&gt;()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ROOT_PATH&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;STIE_PATH&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;LIB_PATH&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ROOT_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Lib/&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;TEST_PATH&amp;#39;&lt;/span&gt;,&#9;&lt;span style="color:#a6e22e"&gt;ROOT_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Test/&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spl_autoload_register&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;($p_strClassName){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$arrClassName &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;explode&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;\\&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;trim&lt;/span&gt;($p_strClassName, &lt;span style="color:#e6db74"&gt;&amp;#39;\\&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($arrClassName)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($arrClassName[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$strPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ROOT_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;implode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;, $arrClassName)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$strPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LIB_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;implode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;DIRECTORY_SEPARATOR&lt;/span&gt;, $arrClassName)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;is_file&lt;/span&gt;($strPath)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; $strPath;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;File not find : &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$strPath);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在运行测试代码&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpunit --bootstrap Test/Bootstrap.php Test/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出现了一些警报和错误。其中一个提示找不到PHPUnit_Extensions_Story_TestCase文件：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP Warning: include(/usr/share/nginx/html/tutorial/mars/Lib/PHPUnit_Extensions_Story_TestCase.php): failed to open stream: No such file or directory in /usr/share/nginx/html/tutorial/mars/Test/Bootstrap.php on line 20&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这文件是一个PHPUnit的基于故事的行为驱动开发（BDD）扩展，于是上网找了下想安装。&lt;/p&gt;&#10;&lt;p&gt;PHPUnit现在只支持Composer安装，如果用PEAR安装会提示失败&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo pear channel-discover pear.phpunit.de&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Discovering channel pear.phpunit.de over http:// failed with message: channel-add: Cannot open &lt;span style="color:#e6db74"&gt;&amp;#34;http://pear.phpunit.de/channel.xml&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;File http://pear.phpunit.de:80/channel.xml not valid &lt;span style="color:#f92672"&gt;(&lt;/span&gt;received: HTTP/1.1 &lt;span style="color:#ae81ff"&gt;410&lt;/span&gt; Gone&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Trying to discover channel pear.phpunit.de over https:// instead&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Discovery of channel &lt;span style="color:#e6db74"&gt;&amp;#34;pear.phpunit.de&amp;#34;&lt;/span&gt; failed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;channel-add: Cannot open &lt;span style="color:#e6db74"&gt;&amp;#34;https://pear.phpunit.de/channel.xml&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;File https://pear.phpunit.de:443/channel.xml not valid &lt;span style="color:#f92672"&gt;(&lt;/span&gt;received: HTTP/1.1 &lt;span style="color:#ae81ff"&gt;410&lt;/span&gt; Gone&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;)))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;先安装&lt;a class="link" href="https://getcomposer.org/doc/00-intro.md" target="_blank" rel="noopener"&#10; &gt;Composer&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -sS https://getcomposer.org/installer | php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mv composer.phar /usr/local/bin/composer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;composer -V&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建一个composer.json，以便自动下载相关的库&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;require-dev&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;phpunit/phpunit&amp;#34;: &amp;#34;4.7.*&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;phpunit/phpunit-selenium&amp;#34;: &amp;#34;&amp;gt;=1.4&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;phpunit/dbunit&amp;#34;: &amp;#34;&amp;gt;=1.3&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;phpunit/phpunit-story&amp;#34;: &amp;#34;*&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;phpunit/php-invoker&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;autoload&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;psr-0&amp;#34;: {&amp;#34;&amp;#34;: &amp;#34;src&amp;#34;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;config&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;bin-dir&amp;#34;: &amp;#34;bin/&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行composer，注意：composer在国内慢的要死，可以参照&lt;a class="link" href="http://www.zhihu.com/question/24997679" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;composer install --dev&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;便会在同级目录下面生成一个vendor目录，各自的依赖库都下载在里面，并且生成了autolaod.php，用于加载相关的类库。编辑Bootstarp.php增加一行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ROOT_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;vendor/autoload.php&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次运行PHPUnit&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 mars&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ phpunit --bootstrap Test/Bootstrap.php Test/KM/Client/RPCTest&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHPUnit 4.7.7 by Sebastian Bergmann and contributors.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EES&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;540&lt;/span&gt; ms, Memory: 14.25Mb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;There were &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; errors:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Test&lt;span style="color:#ae81ff"&gt;\K&lt;/span&gt;M&lt;span style="color:#ae81ff"&gt;\C&lt;/span&gt;lient&lt;span style="color:#ae81ff"&gt;\R&lt;/span&gt;PCTest::testGet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stream_socket_client&lt;span style="color:#f92672"&gt;()&lt;/span&gt;: unable to connect to tcp://127.0.0.1:9001 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Connection refused&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/Stream.php:19&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/Stream.php:16&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/RPC.php:174&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/RPC.php:141&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/RPC.php:130&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Test/Client/RPCTest.php:21&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Test/Client/RPCTest.php:21&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; Test&lt;span style="color:#ae81ff"&gt;\K&lt;/span&gt;M&lt;span style="color:#ae81ff"&gt;\C&lt;/span&gt;lient&lt;span style="color:#ae81ff"&gt;\R&lt;/span&gt;PCTest::testSendGet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stream_socket_client&lt;span style="color:#f92672"&gt;()&lt;/span&gt;: unable to connect to tcp://127.0.0.1:9001 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Connection refused&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/Stream.php:19&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/Stream.php:16&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/RPC.php:174&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/RPC.php:141&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Lib/Client/RPC.php:116&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Test/Client/RPCTest.php:26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/nginx/html/tutorial/mars/Test/Client/RPCTest.php:26&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FAILURES!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Tests: 2, Assertions: 0, Errors: 2, Skipped: 1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这下子没有警报了，只有详细的测试错误报告。刚才的测试代码里面testRecvGet方法依赖于testSendGet，一旦后者失败了，前者便会被跳过。&lt;br&gt;&#10;启动服务端再次运行测试代码&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 mars&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ phpunit --colors --bootstrap Test/Bootstrap.php Test/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHPUnit 4.7.7 by Sebastian Bergmann and contributors.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Time: &lt;span style="color:#ae81ff"&gt;496&lt;/span&gt; ms, Memory: 14.25Mb&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OK &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; tests, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; assertions&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这下子全部测试通过了。&lt;/p&gt;&#10;&lt;p&gt;前面运行测试是这样的：phpunit –bootstrap Test/Bootstrap.php Test/。–bootstrap是指在运行测试时首先加载的文件可以在这里面定义一些配置，自动加载规则，最后一个参数Test/是指要测试的目录，也可以指明运行某个测试用例，比如Test/Client/RPCTest，指运行RPCTest这个测试用例。&lt;/p&gt;&#10;&lt;p&gt;PHPUnit还有许多其他的&lt;a class="link" href="https://phpunit.de/manual/current/zh_cn/textui.html#textui.clioptions" target="_blank" rel="noopener"&#10; &gt;命令行参数选项&lt;/a&gt;，如果每次这么输入也挺麻烦的，可以做成配置文件，加载运行就好了，比如phpunit.xml.dist&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;backupGlobals=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;backupStaticAttributes=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;colors=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;convertErrorsToExceptions=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;convertNoticesToExceptions=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;convertWarningsToExceptions=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;processIsolation=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;stopOnFailure=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;syntaxCheck=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;bootstrap=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Test/Bootstrap.php&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;testsuites&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Lib Test Suite&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;./Test/&lt;span style="color:#f92672"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/testsuites&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/phpunit&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后运行：phpunit -c phpunit.xml.dist 就可以了，更多&lt;a class="link" href="https://phpunit.de/manual/current/zh_cn/appendixes.configuration.html" target="_blank" rel="noopener"&#10; &gt;XML配置参考这里&lt;/a&gt;。还可以在这基础上更改执行配置，比如phpunit -c phpunit.xml.dist Test/Client/RPCTest，便是依照配置仅运行RPCTest。&lt;/p&gt;&#10;&lt;p&gt;以前挺纠结要不要写测试代码，一方面有测试代码的话，每次变更可以自动检测是否通过，另一方面，详细的测试用例需要大量时间去考虑，并且多数情况下都是服务模块之间的互相调用，难以预估结果，超出单元测试范围。现在看来写的这部门测试代码除了验证程序是否准确外，还可以作为示例文档。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/20769745/phpunit-failed-opening-required-phpunit-extensions-story-testcase-php" target="_blank" rel="noopener"&#10; &gt;PHPUnit: Failed opening required `PHPUnit_Extensions_Story_TestCase.php`&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/28455906/issues-while-installing-pear-phpunit-de-phpunit" target="_blank" rel="noopener"&#10; &gt;Issues while installing pear.phpunit.de/PHPUnit&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/zh/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95" target="_blank" rel="noopener"&#10; &gt;单元测试&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://coolshell.cn/articles/8209.html" target="_blank" rel="noopener"&#10; &gt;“单元测试要做多细？”&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/news/2012/02/I-Hate-Unit-Test" target="_blank" rel="noopener"&#10; &gt;我讨厌单元测试：滕振宇谈如何进行单元测试&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/articles/road-of-automated-unit-testing-practices" target="_blank" rel="noopener"&#10; &gt;自动化单元测试实践之路&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://jtreminio.com/2013/03/unit-testing-tutorial-introduction-to-phpunit/" target="_blank" rel="noopener"&#10; &gt;Unit Testing Tutorial Part I: Introduction to PHPUnit&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>MySQL秒杀优化</title><link>https://courages.us/%E7%A7%92%E6%9D%80/</link><pubDate>Sun, 12 Jul 2015 17:08:24 +0800</pubDate><guid>https://courages.us/%E7%A7%92%E6%9D%80/</guid><description>&lt;p&gt;今天学习了&lt;a class="link" href="http://weibo.com/dbatools" target="_blank" rel="noopener"&#10; &gt;楼方鑫先生&lt;/a&gt;的 &lt;a class="link" href="http://www.infoq.com/cn/presentations/seckill-solution-based-sql" target="_blank" rel="noopener"&#10; &gt;《基于SQL的秒杀解决方案》&lt;/a&gt;，讲解了如何定位和优化秒杀业务中问题。&lt;br&gt;&#10;首先介绍了库存业务，库存可以分为前端库存，后端库存，实体库存。秒杀时，存在的主要问题&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;库存数据不准确，下单、付款后，得知零库存；超卖或少卖&lt;/li&gt;&#10;&lt;li&gt;废单较多，只下单不付款，转化率低&lt;/li&gt;&#10;&lt;li&gt;热点商品，拖垮整个站&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;秒杀过程中，需要解决的技术点包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;余额减一&lt;/li&gt;&#10;&lt;li&gt;操作明细，方便追溯对账，防止一个帐号多次参与&lt;/li&gt;&#10;&lt;li&gt;完整事务，保障记录明细与扣减库存同时完成&lt;/li&gt;&#10;&lt;li&gt;数据落地，内存数据不可靠&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;针对库存技术要求，做了多个库存解决方案，比如Mysql + Read /Write Cache 。Read Cache方案不足是读有延迟影响用户体验；Write Cache方案存在多个APP写数据不一致性。Mysql + Cache + NoSQL方案则太复杂未实现。&lt;/p&gt;&#10;&lt;p&gt;于是又重新回到优化Mysql上。Mysql优势在于事务机制成熟，程序稳定。存在技术难点：单行并发，热点商品，瞬间压力，前一分钟，千万用户，容易堵塞，拖垮网站。于是从以下几个方面进行优化&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;事务优化，单行更新&lt;/li&gt;&#10;&lt;li&gt;并发优化，最大并发数&lt;/li&gt;&#10;&lt;li&gt;排队优化，抢同一商品&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;分析秒杀时的处理逻辑，扫描系统代码，发现大部分程序都在等待确认Update记录数，才提交事务。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;开启事务&lt;/li&gt;&#10;&lt;li&gt;Insert库存明细&lt;/li&gt;&#10;&lt;li&gt;Update库存余额&lt;/li&gt;&#10;&lt;li&gt;提交事务&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在良好设计下，Mysql的Insert操作，不使用自增列是不会阻塞请求。但是Mysql的Update同一条记录是串行的，需要等远程客户端发送提交命令后才能释放锁，让其他会话继续。简单的更新操作，不考虑IO和锁冲突，一条语句执行的时间大约是0.1ms，一般条件下的网络时延为0.4-0.8ms，即等待事务提交通知的时间比真正SQL执行的时间长数倍。&lt;br&gt;&#10;于是扩展了SQL语法（&lt;a class="link" href="http://www.onexsoft.com/onesql" target="_blank" rel="noopener"&#10; &gt;OneSQL&lt;/a&gt;），指定在Update执行完后自动提交，不需要等待客户端发送提交命令，从而节约这一个网络来回的事务等待时间，提升网络性能。&lt;/p&gt;&#10;&lt;p&gt;秒杀时如果遇到大量请求需要进行排队，以免太多的请求拖垮Mysql&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;在应用层排队的缺点，应用需要改造，使用统一框架（需要考虑跨语言)，应用集群扩容时，控制不准确（连接数分配）&lt;/li&gt;&#10;&lt;li&gt;在Mysql排队的优点，应用改造极少，只需修改少量SQL语句，无需统一框架，排队精确，发挥InnoDB性能。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;于是开发了兼容Mysql的分布式数据访问层（&lt;a class="link" href="http://www.onexsoft.com/oneproxy" target="_blank" rel="noopener"&#10; &gt;OneProxy&lt;/a&gt;），为并发请求进行排队。&lt;/p&gt;&#10;&lt;p&gt;另外，还对热点商品进行独立数据库拆分和优化。目前，双十一前商品便已挂出，用户可以收藏或预购，对于商家而言可以准备更多商品；对于平台而言可以预先发现热点商品做优化。&lt;/p&gt;&#10;&lt;p&gt;总结，对于业务优化，需要循序渐进，深入了解业务逻辑和技术点，比较不同的解决方案，就算是平常的update操作也有优化空间；同时需要从其他方面进行特定优化，如高并发排队，热点数据分离等。&lt;/p&gt;&#10;&lt;p&gt;除了后端数据库优化，对于秒杀抽奖业务，问题的解决核心就是控制单位时间内的流量，使其不超过后端的处理能力。前端的做法包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;分批次（少量多次)进行秒杀&lt;/li&gt;&#10;&lt;li&gt;先玩游戏再抢购，如抽奖&lt;/li&gt;&#10;&lt;li&gt;随机过滤掉部分请求，仅部分进入系统，如1/10&lt;/li&gt;&#10;&lt;li&gt;阈值控制，一旦达到阈值，不再接收新请求&lt;/li&gt;&#10;&lt;li&gt;预约排号，未排号用户返回失败（用户分类）&lt;/li&gt;&#10;&lt;li&gt;验证码验证&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;另外，&lt;a class="link" href="http://www.onexsoft.com/oneproxy/oneproxy-connection-pool" target="_blank" rel="noopener"&#10; &gt;OneProxy 提供的连接池功能&lt;/a&gt;对于PHP非常有用。PHP运行在CGI下面，每一个请求到来便需要重新创建一个数据库连接与Mysql进行交互，并发量大量的情况下便会出现：too many connetion，乃至拖垮数据库：mysql server has gone away，影响其他业务。因此Mysql连接池，对于PHP显得非常重要。&lt;/p&gt;&#10;&lt;p&gt;更新：&lt;a class="link" href="http://www.infoq.com/cn/presentations/the-use-of-minority-languages-in-venture-company" target="_blank" rel="noopener"&#10; &gt;小米网在开发抢购系统&lt;/a&gt;的时候，最早使用PHP + Mysql碰到了一些问题，例如并发性能，数据一致性，在OneSQL上面都已经做了改进优化，只是小米自己使用Go语言重构，开发大秒系统（BigTap）。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.iteye.com/problems/101435" target="_blank" rel="noopener"&#10; &gt;限量秒杀等高并发活动的正确性如何保证？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://imysql.com/2014/06/07/mysql-percona-mariadb-onesql-tpcc-benchmark.shtml" target="_blank" rel="noopener"&#10; &gt;MySQL 5.6.17/Percona5.6.16/MariaDB 10.0.11/OneSQL 5.6.16 TpmC测试&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://coolshell.cn/articles/6470.html" target="_blank" rel="noopener"&#10; &gt;由12306.cn谈谈网站性能技术&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.csdn.net/article/2014-11-07/2822545" target="_blank" rel="noopener"&#10; &gt;“米粉节”背后的故事——小米网抢购系统开发实践&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.csdn.net/article/2014-11-28/2822858" target="_blank" rel="noopener"&#10; &gt;Web系统大规模并发——电商秒杀与抢购&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.onexsoft.com/oneproxy/oneproxy-connection-pool" target="_blank" rel="noopener"&#10; &gt;OneProxy : 如何给PHP页面以及其他Ruby/Python/Go程序添加连接池功能？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/LinkedDestiny/swoole-doc/blob/master/03.Timer%E5%AE%9A%E6%97%B6%E5%99%A8%E3%80%81%E5%BF%83%E8%B7%B3%E6%A3%80%E6%B5%8B%E5%8F%8ATask%E8%BF%9B%E9%98%B6%E5%AE%9E%E4%BE%8B%EF%BC%9Amysql%E8%BF%9E%E6%8E%A5%E6%B1%A0.md" target="_blank" rel="noopener"&#10; &gt;基于Swoole实现的Mysql连接池&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP ZeroMQ开发</title><link>https://courages.us/php-zeromq/</link><pubDate>Fri, 10 Jul 2015 17:30:31 +0800</pubDate><guid>https://courages.us/php-zeromq/</guid><description>&lt;p&gt;&lt;a class="link" href="http://zeromq.org/" target="_blank" rel="noopener"&#10; &gt;ZeroMQ&lt;/a&gt;的名字有点巧妙，看起来是个MQ却加了个0，变得不是MQ。ZeroMQ是一个面向消息传递的网络通信框架，支持程序在进程内部部通信，进程之间通信，网络间通信，多播等。ZeroMQ对Socket进行了封装，支持多种网络结构范式如Request/Reply，Pub/Sub，Pull/Push，中介，路由等，还可以在这些模式再次扩展，动态扩容程序和分布式任务开发，能够轻易搭建服务程序集群。&lt;/p&gt;&#10;&lt;p&gt;ZeroMQ与支持AMQP的消息中间件不一样，ZeroMQ是一个网络通信库，需要自行实现中间节点和消息的管理。&lt;/p&gt;&#10;&lt;p&gt;在CentOS安装ZeroMQ4&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/zeromq/zeromq4-x.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd zeromq4-x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./autogent.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#声明libzmq库的位置&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/ld.so.conf.d/libzmq.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#内容：/usr/local/lib&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ldconfig&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ZeroMQ支持多种编程语言，也包括PHP。php-zmq安装&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/mkoppanen/php-zmq.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd php-zmq&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑PHP.ini增加扩展信息&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[zeromq]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension = zmq.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看扩展是否加载成功：php -m | grep php。&lt;br&gt;&#10;先写一个简单请求-应答，首先是服务端reply.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5559&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $strMessage&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;From Server1:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是客户端request.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REQ&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://localhost:5559&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello From Client:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;uniqid&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分别在不同终端预先一下程序&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#请求者可以先启动&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php request.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#另一个终端&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php reply.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用ZeroMQ进行通信的步骤&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;使用ZMQContext创建一个上下文&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;使用上下文初始化ZMQSocket，这里需要指明socket类型（ZMQ::SOCKET_开头），组合模式包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;PUB，SUB&lt;/li&gt;&#10;&lt;li&gt;REQ，REP&lt;/li&gt;&#10;&lt;li&gt;REQ，ROUTER (take care, REQ inserts an extra null frame)&lt;/li&gt;&#10;&lt;li&gt;DEALER，REP (take care, REP assumes a null frame)&lt;/li&gt;&#10;&lt;li&gt;DEALER，ROUTER&lt;/li&gt;&#10;&lt;li&gt;DEALER，DEALER&lt;/li&gt;&#10;&lt;li&gt;ROUTER，ROUTER&lt;/li&gt;&#10;&lt;li&gt;PUSH，PULL&lt;/li&gt;&#10;&lt;li&gt;PAIR，PAIR&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;分类包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;轮询，REQ，PUSH，DEALER&lt;/li&gt;&#10;&lt;li&gt;多播，PUB&lt;/li&gt;&#10;&lt;li&gt;公平排队，REP，SUB，PULL，DEALER&lt;/li&gt;&#10;&lt;li&gt;明确寻址，ROUTER&lt;/li&gt;&#10;&lt;li&gt;单播，PAIR&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;如果是服务端就bind，如果是客户端就conncet，这里的连接信息支持&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;进程内部通信，inproc://&lt;/li&gt;&#10;&lt;li&gt;进程间通信，ipc://&lt;/li&gt;&#10;&lt;li&gt;网络间通信，tcp://&lt;/li&gt;&#10;&lt;li&gt;多播，pgm://&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;使用send/recv发送/接收消息&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;使用ZeroMQ创建通信比socket简单多了，与stream_socket差不多。但是使用ZeroMQ，客户端可以先启动而不用管服务端是否已经启动了，等服务端连接上了便会自动传递消息，还可以维持节点之间的心跳。&lt;/p&gt;&#10;&lt;p&gt;ZeroMQ与socket通信是不一样的。ZeroMQ是无状态的，对socket的细节进行了封装，不能知道彼此的socket连接信息，仅能接收和发送消息；ZeroMQ能够使用一个socket与多个节点进行通信，具有极高的性能。&lt;/p&gt;&#10;&lt;p&gt;再回头看一下服务端程序，这里采用while循环来处理，亦即同一时刻只能处理一个请求，多个请求排队直到被轮询到，客户端的发送和接收都是同步等待。由于不知道客户端信息，也不能在子进程内处理完成再返回。这里就需要用到ZeroMQ各种范式的组合，比如下面这个&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/07/fig16.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="fig16" class="gallery-image" data-flex-basis="250px" data-flex-grow="104" height="287" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/07/fig16-300x287.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;这里使用ROUTER和DEALER作为中介，转发请求，客户端可以异步发送求，不用等待服务端响应。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pFrontend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_ROUTER&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pBackend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_DEALER&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pFrontend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5559&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pBackend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5560&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPoll &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQPoll&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPoll&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;($pFrontend, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;POLL_IN&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPoll&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;($pBackend, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;POLL_IN&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$arrRead &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $arrWrite &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$nEvent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pPoll&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;poll&lt;/span&gt;($arrRead, $arrWrite);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($nEvent &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt;($arrRead &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $pSocket){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($pSocket &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $pFrontend){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pSocket&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$nMore &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pSocket&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getSockOpt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKOPT_RCVMORE&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$pBackend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;($strMessage,$nMore &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MODE_SNDMORE&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$nMore){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pSocket &lt;span style="color:#f92672"&gt;===&lt;/span&gt; $pBackend){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pSocket&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$nMore &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pSocket&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getSockOpt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKOPT_RCVMORE&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$pFrontend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;($strMessage,$nMore &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MODE_SNDMORE&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$nMore){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后更改服务端reply.php，不再绑定监听，而不是连接到DEALER上&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pServer-&amp;gt;bind(&amp;#34;tcp://*:5555&amp;#34;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://localhost:5560&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $strMessage&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;From Server1:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里使用ZMQPoll对ZMQSOcket的输入输出事件进行轮询，将ROUTER收到的REQ转发给服务端，将DEALER收到的REP转发给客户端。事实上，还有更简便的方法：使用ZMQDevice将ROUTER和DEALER组合起来&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pFrontend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_ROUTER&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pBackend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_DEALER&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pFrontend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5559&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pBackend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5560&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pDevice &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQDevice&lt;/span&gt;($pFrontend, $pBackend);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pDevice&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ZeroMQ的Pub/Sub的通信模型支持一个发布者发布消息给多个订阅者，也支持一个订阅者从多个发布者订阅消息。首先写一个发布者&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPublisher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_PUB&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPublisher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5563&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pPublisher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MODE_SNDMORE&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pPublisher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;1:We don&amp;#39;t want to see this&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pPublisher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MODE_SNDMORE&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pPublisher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;1:We would like to see this&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是订阅者&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pSubscriber &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_SUB&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pSubscriber&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://localhost:5563&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#可以连接多个发布者&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pSubscriber&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://localhost:5564&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pSubscriber&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setSockOpt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKOPT_SUBSCRIBE&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Read envelope with address&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $address &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pSubscriber&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Read message contents&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $contents &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pSubscriber&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;[%s] %s%s&amp;#34;&lt;/span&gt;, $address, $contents, &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pub/Sub模型，发布者只能发布消息，要求发布消息前，先声明主题（地址），然后发布消息内容；订阅者只能接收消息，先设置订阅主题，然后两次接收，第一次为消息主题，第二次为消息内容。&lt;br&gt;&#10;Pub/Sub模型通消息为单向流动，可以结合其他模型让订阅者与发布者互动，比如REQ\REP。&lt;/p&gt;&#10;&lt;p&gt;ZeroMQ的Push/Pull模型，生产者负责推送消息，消费者负责拉取消息。初看之下Pull/Push模型与Pub/sub模型类似，但是Pull/Push下生产者产生的消息只会投递给一个消费者，并不会发布给全部消费者，适合用于任务投递分配&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/07/fig5.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="fig5" class="gallery-image" data-flex-basis="180px" data-flex-grow="75" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/07/fig5-225x300.png" width="225"&gt;&lt;/a&gt;&lt;br&gt;&#10;Push和Pull都既可作为服务端，也可作为客户端。服务端Push.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPush &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_PUSH&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPush&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5558&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pPush-&amp;gt;connect(&amp;#34;tcp://localhost:5558&amp;#34;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pPush-&amp;gt;connect(&amp;#34;tcp://localhost:5559&amp;#34;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPush&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello Client 1&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端Pull.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPull &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_PULL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pPull-&amp;gt;bind(&amp;#34;tcp://*:5558&amp;#34;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPull&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://localhost:5558&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPull&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://localhost:5559&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pPull&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果同时启动了两个客户端Pull.php，而只启动一个服务端Push.php，那么一次只会有一个客户端接收到消息。也可以以Pull作为主动监听，Push作为被动连接。可以同时接可以Pub/Sub和Pull/Push来处理任务&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/07/fig56.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="fig56" class="gallery-image" data-flex-basis="210px" data-flex-grow="87" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/07/fig56-263x300.png" width="263"&gt;&lt;/a&gt;&lt;br&gt;&#10;如果是用ZeroMQ传递消息收不到，可以按下面这个流程查问题&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/07/chapter1_9.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="chapter1\\_9" class="gallery-image" data-flex-basis="104px" data-flex-grow="43" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/07/chapter1_9-131x300.png" width="131"&gt;&lt;/a&gt;&lt;br&gt;&#10;除了客户端可以连接多个服务端，服务端同样可以绑定多个地址。在REQ/REP模型里，让服务端同时使用IPC（进程间通信）来处理本机的连接&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;tcp://*:5556&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ipc:///tmp/req.ipc&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $message &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello from server1:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$message);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端可以选择走TCP或者IPC进行消息通信&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pContext &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;($pContext, &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REQ&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ipc:///tmp/req.ipc&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pClient-&amp;gt;connect(&amp;#34;tcp://localhost:5556&amp;#34;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello From Client1:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;uniqid&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $strMessage,&lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用ZeroMQ的进程内部消息通信也很简单&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;(), &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REP&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;inproc://reply&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQSocket&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZMQContext&lt;/span&gt;(), &lt;span style="color:#a6e22e"&gt;ZMQ&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SOCKET_REQ&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;inproc://reply&amp;#34;&lt;/span&gt;);;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello From Client1:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;uniqid&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ZeroMQ为消息传递的提供极简的方法，提供了各种连接模型，可以自由扩展。&lt;a class="link" href="http://zguide.zeromq.org/php:all" target="_blank" rel="noopener"&#10; &gt;zguide&lt;/a&gt;更像是一个网络编程指南，指导大家如何利用ZeroMQ搭建各种网络通信模式，提高程序扩展性和健壮性。虽然ZeroMQ解决了进程间和网络间的通信问题，但是各个组件本身进程控制仍然需要自行实现。&lt;/p&gt;&#10;&lt;p&gt;更新：ZeroMQ的作者用C语言创建了另外一个支持多种通用通信范式的socket库：&lt;a class="link" href="http://nanomsg.org/" target="_blank" rel="noopener"&#10; &gt;nanomsg&lt;/a&gt;，可以用来代替ZeroMQ做的那些事，提供了更好的伸缩性，也有对应的&lt;a class="link" href="https://github.com/mkoppanen/php-nano" target="_blank" rel="noopener"&#10; &gt;PHP扩展&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/anjuke/zguide-cn" target="_blank" rel="noopener"&#10; &gt;ZMQ 指南&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/josezap1/zero-mq-and-cakephp" target="_blank" rel="noopener"&#10; &gt;ZeroMQ in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/IanBarber/zeromq-is-the-answer" target="_blank" rel="noopener"&#10; &gt;zeromq is the answer&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://toys.lerdorf.com/archives/57-ZeroMQ-&amp;#43;-libevent-in-PHP.html" target="_blank" rel="noopener"&#10; &gt;ZeroMQ + libevent in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/fcrippa/europycon2011-implementing-distributed-application-using-zeromq" target="_blank" rel="noopener"&#10; &gt;Europycon2011: Implementing distributed application using ZeroMQ&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tim.dysinger.net/posts/2013-09-16-getting-started-with-nanomsg.html" target="_blank" rel="noopener"&#10; &gt;Getting Started with ‘nanomsg’&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bravenewgeek.com/a-look-at-nanomsg-and-scalability-protocols/" target="_blank" rel="noopener"&#10; &gt;A Look at Nanomsg and Scalability Protocols (Why ZeroMQ Shouldn’t Be Your First Choice)&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP Socket通信</title><link>https://courages.us/php-socket%E9%80%9A%E4%BF%A1/</link><pubDate>Sun, 05 Jul 2015 23:32:42 +0800</pubDate><guid>https://courages.us/php-socket%E9%80%9A%E4%BF%A1/</guid><description>&lt;p&gt;前一篇介绍了跨语言的服务调用框架&lt;a class="link" href="https://courages.us/php-rpc%e5%bc%80%e5%8f%91%e4%b9%8bthrift/" target="_blank" rel="noopener"&#10; &gt;Thrift&lt;/a&gt;，模块与模块之间调用，网络通信必不可少。这里具体介绍下如何使用PHP socket客户端与服务端进行通信。&lt;/p&gt;&#10;&lt;p&gt;PHP 的Socket扩展是基于流行的BSD sockets，实现了和socket通讯功能的底层接口，它可以和通用客户端一样当做一个socket服务器。这里的通用客户端是指stream_socket_*系列封装的函数。&lt;/p&gt;&#10;&lt;p&gt;首先写一个socket服务端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SOL_TCP&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pSocket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorCode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorMsg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($p_strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;, $p_nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;, $p_nProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SOL_TCP&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//参数验证&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strHost&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_strHost;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nPort&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nPort;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nProtocol&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nProtocol;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_bind&lt;/span&gt;()){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_listen&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_create&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;AF_INET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOCK_STREAM&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nProtocol&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_bind&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_bind&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strHost&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nPort&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $bRes;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_listen&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_listen&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) ;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $bRes;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;accept&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_accept&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;accept&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;socket_getpeername&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, $address, $port)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Client &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$address&lt;/span&gt;&lt;span style="color:#e6db74"&gt; : &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$port&lt;/span&gt;&lt;span style="color:#e6db74"&gt; is now connected to us. &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;hello world from server&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$mxData &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($mxData);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($mxData &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;client disconnected.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Client: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;trim&lt;/span&gt;($mxData)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$mxMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_read&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;PHP_BINARY_READ&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($mxMessage &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $mxMessage;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($p_strMessage){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_write&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, $p_strMessage, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt; ($p_strMessage));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $bRes;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_last_error&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorMsg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_strerror&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//throw new Exception(&amp;#34;exception:&amp;#34;.$this-&amp;gt;strErrorMsg , $this-&amp;gt;strErrorCode);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25003&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerSocket&lt;/span&gt;($strHost, $nPort);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里对socket_*系列函数进行了包装，创建socket服务端的步骤&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用&lt;a class="link" href="http://php.net/manual/zh/function.socket-create.php" target="_blank" rel="noopener"&#10; &gt;socket_create&lt;/a&gt;创建socket（套接字）。第一个参数AF_INET指IPV4网络协议，TCP和UDP均可使用，对应IPV6网络协议为AF_INET6，也可以使用UNIX socket协议AF_UNIX，作进程间通信&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;。第二个参数对应套接字类型，SOCK_STREAM对应TCP协议使用，SOCK_DGRAM对应UDP协议使用，还有SOCK_SEQPACKET，SOCK_RAW，SOCK_RDM等类型。第三个为协议类型，TCP协议对应常量SOL_TCP，UDP协议对应常量SOL_UDP，其他协议可以从getprotobyname函数获取。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用socket_bind将套接字绑定到对应的主机端口或者UNIX socket上&lt;/li&gt;&#10;&lt;li&gt;使用socket_listen监听该套接字上的连接&lt;/li&gt;&#10;&lt;li&gt;使用socket_accept接收套接字上的请求连接，返回一个新的套接字用于与客户端通信。如果没有连接接入，将会阻塞住；如果有多个连接，使用第一个达到的连接。&lt;/li&gt;&#10;&lt;li&gt;开始通信，使用socket_read获取请求信息，使用socket_write返回响应结果&lt;/li&gt;&#10;&lt;li&gt;使用socket_close关闭连接，包括原始的和socket_accept产生的套接字&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这个过程中，可以使用socket_last_error和socket_strerror获取错误信息。接着创建客户端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClientSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SOL_TCP&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $pSocket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorCode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorMsg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($p_strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;, $p_nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;, $p_nProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SOL_TCP&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//参数验证&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strHost&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_strHost;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nPort&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nPort;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nProtocol&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nProtocol;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;()){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_create&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;AF_INET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOCK_STREAM&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nProtocol&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pSocket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_connect&lt;/span&gt;($pSocket, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strHost&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nPort&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $bRes;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strBuffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($strBuffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_read&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;PHP_BINARY_READ&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $strBuffer;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $strMessage;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($p_strMessage){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_write&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, $p_strMessage, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($p_strMessage));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;($p_strMessage){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_send&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt; , $p_strMessage , &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($p_strMessage) , &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;recv&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strBuffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_recv&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, $strBuffer, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt; , &lt;span style="color:#a6e22e"&gt;MSG_WAITALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$bRes){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;.=&lt;/span&gt;$strBuffer;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $strMessage;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_log&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_last_error&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorMsg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_strerror&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//throw new Exception(&amp;#34;exception:&amp;#34;.$this-&amp;gt;strErrorMsg , $this-&amp;gt;strErrorCode);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25003&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$nProtocol = getprotobyname($strProtocol);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClientSocket&lt;/span&gt;($strHost, $nPort);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Some Thing :&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;uniqid&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; var_dump($pClient-&amp;gt;recv());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;$pClient-&amp;gt;send(&amp;#39;hello&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;var_dump($pClient-&amp;gt;recv());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端的创建步骤:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用socket_create创建socket套接字，与服务端对应&lt;/li&gt;&#10;&lt;li&gt;使用socket_connect连接到服务端的地址或UNIX socket&lt;/li&gt;&#10;&lt;li&gt;开始通信，可以使用socket_write和socket_read向套接字写入和读取信息，也可以使用socket_send和socket_recv发送和接收信息&lt;/li&gt;&#10;&lt;li&gt;使用socket_close关闭连接&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;运行服务端程序&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php serversocket.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在另一个终端里运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant socket&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# netstat -apn | grep 25003&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:25003 0.0.0.0:* LISTEN 12139/php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果运行服务端失败，提示 socket_bind(): unable to bind address [98]: Address already in use ，则是端口绑定失败。查看端口占用&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@vagrant socket&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# netstat -apn | grep 25003&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tcp &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 127.0.0.1:25003 127.0.0.1:36618 TIME_WAIT -&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该端口处于TIME_WAIT状态，需要再等一会儿才会释放。这是因为TCP连接关闭需要四次握手，服务端主动关闭了连接，但是未收到客户端发过来的关闭确认，导致处于等待状态，具体原因见火丁笔记&lt;a class="link" href="http://huoding.com/2013/12/31/316" target="_blank" rel="noopener"&#10; &gt;《再叙TIME_WAIT》&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;如果服务端已经运行成功，在另一个终端里运行客户端程序&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php clientsocket.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是一个简单服务端/客户端请求应答模型，通常服务端会一直处于监听状态，处理新的请求，重新写一个循环监听的服务端&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SelectServerSocket&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrRead &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrWrite &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $arrExp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$arrRead &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $arrClient;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_select&lt;/span&gt;($arrRead, $arrWrite, $arrExp, &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($arrRead &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $pSocket){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($pSocket &lt;span style="color:#f92672"&gt;==&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$arrClient[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($bRes &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;$nKey &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_search&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, $arrClient);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($arrClient[$nKey]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//usleep(100);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25003&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SelectServerSocket&lt;/span&gt;($strHost, $nPort);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在循环里面使用&lt;a class="link" href="http://php.net/manual/zh/function.socket-select.php" target="_blank" rel="noopener"&#10; &gt;socket_select&lt;/a&gt;查询有可以读的套接字，如果套接字为原始监听的套接字，则使用socket_accept获取新接入的通信套接字进行通信；如果是通信套接字，则与客户端进行交互。&lt;/p&gt;&#10;&lt;p&gt;这里socket_select($arrRead, $arrWrite, $arrExp, null)的第四个参数为null，表示可以无限阻塞，如果为0则不阻塞立即返回，其他大于0值则等待超时。&lt;br&gt;&#10;socket_recv($this-&amp;gt;pSocket, $strBuffer, 1024 , MSG_WAITALL)的第四个参数为MSG_WAITALL，表示阻塞读取结果。&lt;br&gt;&#10;socket_read ($this-&amp;gt;pSocket, 1024, PHP_BINARY_READ )的第三个参数PHP_BINARY_READ表示读取以\0结束，PHP_NORMAL_READ表示读取以\n或\r结束&lt;/p&gt;&#10;&lt;p&gt;在终端里运行服务端，会一直在那里等待新的连接。这时候运行客户端，客户端确也阻塞住了。解决的办法有两种：超时设置和非阻塞设置。给ClientSocket类增加超时和阻塞设置的方法&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setTimeOut&lt;/span&gt;($p_nSendTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, $p_nRecvTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$nSend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)$p_nSendTimeOut;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$nRecv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)$p_nRecvTimeOut;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrSend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $nSend, &lt;span style="color:#e6db74"&gt;&amp;#39;usec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)(($p_nSendTimeOut &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nSend) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrRecv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $nRecv, &lt;span style="color:#e6db74"&gt;&amp;#39;usec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)(($p_nRecvTimeOut &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nRecv) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_option&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOL_SOCKET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SO_RCVTIMEO&lt;/span&gt;, $arrSend);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_option&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOL_SOCKET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SO_SNDTIMEO&lt;/span&gt;, $arrRecv);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setBlock&lt;/span&gt;($p_bType &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($p_bType){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_block&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_nonblock&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端端运行前，先设置一下超时或非阻塞即，此时程序不会再阻塞了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClientSocket&lt;/span&gt;($strHost, $nPort);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pClient&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setTimeOut&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pClient-&amp;gt;setBlock(false);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//do request here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样在服务端设置超时和非阻塞也是可以的，给ServerSocket增加超时和非阻塞设置的方法&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_setNoBlock&lt;/span&gt;($p_pSocket){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_nonblock&lt;/span&gt;($p_pSocket);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_setTimeOut&lt;/span&gt;($p_pSocket, $p_nSendTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, $p_nRecvTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$nSend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)$p_nSendTimeOut;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$nRecv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)$p_nRecvTimeOut;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrSend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $nSend, &lt;span style="color:#e6db74"&gt;&amp;#39;usec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)(($p_nSendTimeOut &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nSend) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrRecv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;sec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $nRecv, &lt;span style="color:#e6db74"&gt;&amp;#39;usec&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;int&lt;/span&gt;)(($p_nRecvTimeOut &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nRecv) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_option&lt;/span&gt;($p_pSocket, &lt;span style="color:#a6e22e"&gt;SOL_SOCKET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SO_RCVTIMEO&lt;/span&gt;, $arrSend);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;socket_set_option&lt;/span&gt;($p_pSocket, &lt;span style="color:#a6e22e"&gt;SOL_SOCKET&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SO_SNDTIMEO&lt;/span&gt;, $arrRecv);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将SelectServerSocket的socket_accept后产生的连接设置为非阻塞&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrRead &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrWrite &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $arrExp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_setNoBlock&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次运行服务端，客户端也不会阻塞了。&lt;/p&gt;&#10;&lt;p&gt;在while循环里面使用socket_select进行查询，效率比较低下，有先的连接要等下次循环才能处理；有时候并没有连接需要处理，也一直在循环。可以结合前面介绍过的&lt;a class="link" href="https://courages.us/php-%e4%ba%8b%e4%bb%b6%e9%a9%b1%e5%8a%a8%e5%bc%80%e5%8f%91/" target="_blank" rel="noopener"&#10; &gt;PHP Libev扩展&lt;/a&gt;进行监听&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvServerSocket&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_onConnect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pReadClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pReadWatcher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pSocket&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_onConnect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25003&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvServerSocket&lt;/span&gt;($strHost, $nPort);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码看起来简单了很多。当原始套接字监听到可读事件时，便为新的套接字也创建可读事件监听 ，在事件里面处理新的连接。&lt;/p&gt;&#10;&lt;p&gt;通常的服务端程序是一个进程监听原始套接字，然后交由其他进程/线程处理新的连接套接字，与客户端进行交互，提升服务端性能。这样子又涉及到了多进程/多线程的控制、通信，需要一套完善的体系才行。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MulProcessServerSocket&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvServerSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_execute&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;()){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//子进程执行完毕，通知父进程&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_onConnect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//父进程和子进程都会执行下面代码&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//错误处理：创建子进程失败时返回-1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;could not fork&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//父进程会得到子进程号，所以这里是父进程执行的逻辑&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_wait&lt;/span&gt;($status); &lt;span style="color:#75715e"&gt;//等待子进程中断，防止子进程成为僵尸进程。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$pReadClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_execute&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;还可以使用stream_socket_*系列函数来创建sockt服务端和客户端。类似的创建一个客户端与之前的服务端进行交互&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClientStreamSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $pConnetion &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $strAddress &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:2016&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nFlag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;STREAM_CLIENT_CONNECT&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorCode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorMsg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BLOCK&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOBLOCK&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($p_strAddress, $p_nTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, $p_nFlag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;STREAM_CLIENT_CONNECT&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strAddress&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_strAddress;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nTimeOut&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nTimeOut;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nFlag&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nFlag;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_client&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strAddress&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorMsg&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nTimeOut&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nFlag&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;connect exception:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorMsg&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($p_strMessage){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fwrite&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;, $p_strMessage) &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($p_strMessage))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Can not send data&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//接收一行，阻塞至\n结束&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$strMessage = fgets($this-&amp;gt;pConnetion);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//指定长度读取&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$strMessage = fread($this-&amp;gt;pConnetion, 1024);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_recvfrom&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$strMessage = stream_get_contents($this-&amp;gt;pConnetion);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $strMessage;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setContext&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setTimeOut&lt;/span&gt;($p_nTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_set_timeout&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;, $p_nTimeOut);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setBlock&lt;/span&gt;($p_nMode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClientStreamSocket&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BLOCK&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_set_blocking&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;, $p_nMode);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pConnetion&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25003&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$nProtocol = getprotobyname($strProtocol);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strAddress &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $strProtocol&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;://&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$strHost&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$nPort;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pStream &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ClientStreamSocket&lt;/span&gt;($strAddress);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pStream-&amp;gt;setBlock(ClientStreamSocket::NOBLOCK);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$pStream-&amp;gt;setTimeOut(1);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pStream&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pStream&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;hello from client&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($pStream&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pStream&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用stream_socket_*系列函数创建客户端要简单不少&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;首先使用&lt;a class="link" href="http://php.net/manual/zh/function.stream-socket-client.php" target="_blank" rel="noopener"&#10; &gt;stream_socket_client&lt;/a&gt;创建一个socket操作流(stream)&lt;/li&gt;&#10;&lt;li&gt;然后就可以像操作流式文件那样造成socket stream，使用fread和fwrite进行读写操作，也可以使用stream_socket_recvfrom和stream_socket_sendto进行操作&lt;/li&gt;&#10;&lt;li&gt;使用fclose或stream_socket_shutdown关闭连接&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;使用stream_socket_*系列函数创建一个服务端来与之前的客户端进行交互，同样很简单，也与ServerSocket类似&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerStreamSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $strAddress &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp://127.0.0.1:2016&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $nFlag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;STREAM_SERVER_LISTEN&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;BLOCK&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NOBLOCK&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorCode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $strErrorMsg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($p_strAddress, $p_nFlag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;STREAM_SERVER_LISTEN&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strAddress&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_strAddress;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nFlag&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $p_nFlag;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_create&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_server&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strAddress&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorMsg&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt; ){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;create exception:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorMsg&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strErrorCode&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt; ;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;accept&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_accept&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt; ){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt; ;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;accept&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Client&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_get_name&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; is now connected to us. &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;hello world from server&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$mxData &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($mxData);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($mxData &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;client disconnected.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Client:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;trim&lt;/span&gt;($mxData)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;write&lt;/span&gt;($p_strMessage){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$nLen = fwrite($this-&amp;gt;pClient, $p_strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$nLen &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_sendto&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, $p_strMessage);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($nLen &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($p_strMessage))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Can not send data&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//接收一行，阻塞至\n结束&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$strMessage = fgets($this-&amp;gt;pClient);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//指定长度读取&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$strMessage = fread($this-&amp;gt;pClient, 1024);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$strMessage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_recvfrom&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//$strMessage = stream_get_contents($this-&amp;gt;pClient);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $strMessage;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setContext&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setTimeOut&lt;/span&gt;($p_pConnetction, $p_nTimeOut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_set_timeout&lt;/span&gt;($p_pConnetction, $p_nTimeOut);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setBlock&lt;/span&gt;($p_pConnetction, $p_nMode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerStreamSocket&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BLOCK&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_set_blocking&lt;/span&gt;($p_pConnetction, $p_nMode);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SelectServerStreamSocket&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerStreamSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrRead &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrWrite &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $arrExp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$arrClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$arrRead &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $arrClient;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;stream_select&lt;/span&gt;($arrRead, $arrWrite, $arrExp, &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;in_array&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;, $arrRead)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$arrClient[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$nKey &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_search&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;, $arrRead);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($arrRead[$nKey]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt;($arrRead &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $pConnetcion){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$bRes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($bRes &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;$nKey &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_search&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, $arrClient);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($arrClient[$nKey]);;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//usleep(100);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvServerStreamSocket&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ServerStreamSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_onConnect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pReadClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pReadWatcher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pServer&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_onConnect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MulProcessServerStreamSocket&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvServerStreamSocket&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_execute&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_reply&lt;/span&gt;()){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//子进程执行完毕，通知父进程&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_onConnect&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;could not fork&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_wait&lt;/span&gt;($status);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_connect&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$pReadClient &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pClient&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_execute&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strHost &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nPort &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25003&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strProtocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//$nProtocol = getprotobyname($strProtocol);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strAddress &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $strProtocol&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;://&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$strHost&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$nPort;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvServerStreamSocket&lt;/span&gt;($strAddress);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pServer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里演示客户端与服务端交互，都是两步走，先发送一个请求再获取结果。在Thrift RPC远程调用中，既可先发送请求，过一会儿再来获取结果，达到异步交互的目的；也可发送完请求后立即获取结果，达到同步请求的目的。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.codeproject.com/Tips/418814/Socket-Programming-in-PHP" target="_blank" rel="noopener"&#10; &gt;Socket Programming in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.binarytides.com/socket-programming-streams-php/" target="_blank" rel="noopener"&#10; &gt;Socket programming with streams in php&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.binarytides.com/php-socket-programming-tutorial/" target="_blank" rel="noopener"&#10; &gt;PHP Socket programming tutorial&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.51yip.com/php/673.html" target="_blank" rel="noopener"&#10; &gt;php 实例说明 socket通信机制&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2010/10/29/1774.html" target="_blank" rel="noopener"&#10; &gt;Mpass – PHP做Socket服务的解决方案&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://serverfault.com/questions/329845/how-to-forcibly-close-a-socket-in-time-wait" target="_blank" rel="noopener"&#10; &gt;How to forcibly close a socket in TIME_WAIT?&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP RPC开发之Thrift</title><link>https://courages.us/php-rpc%E5%BC%80%E5%8F%91%E4%B9%8Bthrift/</link><pubDate>Sun, 28 Jun 2015 13:38:47 +0800</pubDate><guid>https://courages.us/php-rpc%E5%BC%80%E5%8F%91%E4%B9%8Bthrift/</guid><description>&lt;p&gt;&lt;a class="link" href="https://thrift.apache.org/" target="_blank" rel="noopener"&#10; &gt;Apache Thrift&lt;/a&gt;是一个跨语言的服务部署框架，通过一个中间语言(&lt;a class="link" href="https://thrift.apache.org/docs/idl" target="_blank" rel="noopener"&#10; &gt;IDL&lt;/a&gt;, 接口定义语言)来定义RPC的接口和数据类型，然后通过一个编译器生成不同语言的代码（支持C++，Java，Python，PHP, GO，Javascript，Ruby，Erlang，Perl， Haskell， C#等）,并由生成的代码负责RPC协议层和传输层的实现。&lt;/p&gt;&#10;&lt;p&gt;在CentOS 6.5上安装Thrift&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum -y update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum -y groupinstall &lt;span style="color:#e6db74"&gt;&amp;#34;Development Tools&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#升级autoconf，必须2.65以上&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar xvf autoconf-2.69.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd autoconf-2.69&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#升级automake必须1.14以上&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar xvf automake-1.14.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd automake-1.14&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#升级bsion&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar xvf bison-2.5.1.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd bison-2.5.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装boost&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar xvf boost_1_55_0.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd boost_1_55_0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./bootstrap.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ./b2 install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装thrift，编译会比较久，内存最好1024M以上&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://git-wip-us.apache.org/repos/asf/thrift.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd thrift&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./bootstrap.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#查看版本&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thrift -version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#安装thrift_protocol扩展，仅支持二进制读写&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd thrift/lib/php/src/ext/thrift_protocol&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#这里不需要更改php.ini，已自动在/etc/php.d/thrift_protocol.ini里面添加&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php -m | grep thrift&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thrift的PHP类库位于thrift/lib/php/lib/Thrift目录下面，Thrift对于数据传输格式、数据传输方式，服务器模型均做了定义，方便自行扩展。&lt;/p&gt;&#10;&lt;p&gt;数据传输格式（protocol）是定义的了传输内容，对&lt;a class="link" href="https://thrift.apache.org/docs/types" target="_blank" rel="noopener"&#10; &gt;Thrift Type&lt;/a&gt;的打包解包，包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TBinaryProtocol，二进制格式，TBinaryProtocolAccelerated则是依赖于thrift_protocol扩展的快速打包解包。&lt;/li&gt;&#10;&lt;li&gt;TCompactProtocol，压缩格式&lt;/li&gt;&#10;&lt;li&gt;TJSONProtocol，JSON格式&lt;/li&gt;&#10;&lt;li&gt;TMultiplexedProtocol，利用前三种数据格式与支持多路复用协议的服务端（同时提供多个服务，TMultiplexedProcessor）交互&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;数据传输方式（transport），定义了如何发送（write）和接收（read）数据，包括&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TBufferedTransport，缓存传输，写入数据并不立即开始传输，直到刷新缓存。&lt;/li&gt;&#10;&lt;li&gt;TSocket，使用socket传输&lt;/li&gt;&#10;&lt;li&gt;TFramedTransport，采用分块方式进行传输，具体传输实现依赖其他传输方式，比如TSocket&lt;/li&gt;&#10;&lt;li&gt;TCurlClient，使用curl与服务端交互&lt;/li&gt;&#10;&lt;li&gt;THttpClient，采用stream方式与HTTP服务端交互&lt;/li&gt;&#10;&lt;li&gt;TMemoryBuffer，使用内存方式交换数据&lt;/li&gt;&#10;&lt;li&gt;TPhpStream，使用PHP标准输入输出流进行传输&lt;/li&gt;&#10;&lt;li&gt;TNullTransport，关闭数据传输&lt;/li&gt;&#10;&lt;li&gt;TSocketPool在TSocket基础支持多个服务端管理（需要APC支持），自动剔除无效的服务器&lt;/li&gt;&#10;&lt;li&gt;TNonblockingSocket，非官方实现非阻塞socket&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;服务模型，定义了当PHP作为服务端如何监听端口处理请求&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TForkingServer，采用子进程处理请求&lt;/li&gt;&#10;&lt;li&gt;TSimpleServer，在TServerSocket基础上处理请求&lt;/li&gt;&#10;&lt;li&gt;TNonblockingServer，基于libevent的非官方实现非阻塞服务端，与TNonblockingServerSocket，TNonblockingSocket配合使用&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;另外还定义了一些工厂，以便在Server模式下对数据传输格式和传输方式进行绑定&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;TProtocolFactory，数据传输格式工厂类，对protocol的工厂化生产，包括TBinaryProtocolFactory，TCompactProtocolFactory，TJSONProtocolFactory&lt;/li&gt;&#10;&lt;li&gt;TTransportFactory，数据传输方式工厂类，对transport的工厂化生产，作为server时，需要自行实现&lt;/li&gt;&#10;&lt;li&gt;TStringFuncFactory，字符串处理工厂类&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;其他文件便是异常，字符串处理，自动加载器的定义等等。&lt;/p&gt;&#10;&lt;p&gt;现在开始编写一个简单接IDL文件HelloWorld.thrift&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;namespace php Services.HelloWorld&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service HelloWorld&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; string sayHello(1:string name);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后通过生成器生成PHP文件&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#不指明:server不生成processor。。&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thrift --gen php:server HelloWorld.thrift&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成文件在gen-php目录下面的Services/HelloWord/HelloWorld.php（目录与namesapce定义一致），这是个公共文件，服务端和客户端都需要包括它。其中客户端调用的代码（HelloWorldClient ）已经生成好了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//服务端需要继承该接口&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorldIf&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param string $name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return string&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sayHello&lt;/span&gt;($name);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//提供给客户端调用的方法&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorldClient&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Services\HelloWorld\HelloWorldIf&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sayHello&lt;/span&gt;($name)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send_sayHello&lt;/span&gt;($name);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv_sayHello&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send_sayHello&lt;/span&gt;($name)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;recv_sayHello&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//HelloWord类sayHello方法参数读取&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorld_sayHello_args&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//HelloWord类sayHello方法结果写入&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorld_sayHello_result&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//作为服务端才会生成&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorldProcessor&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而服务端的服务实现代码则需要继承HelloWorldIf 实现代码HelloWorldHandler.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Services\HelloWorld&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorldHandler&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HelloWorldIf&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sayHello&lt;/span&gt;($name)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$name&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编写服务端代码Server.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Services\HelloWorld&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;error_reporting&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;E_ALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;THRIFT_ROOT&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/../../../&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;require_once&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;THRIFT_ROOT&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Thrift/ClassLoader/ThriftClassLoader.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\ClassLoader\ThriftClassLoader&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ThriftClassLoader&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;registerNamespace&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Thrift&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;THRIFT_ROOT&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;registerDefinition&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Service&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;THRIFT_ROOT&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/gen-php&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;register&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Exception\TException&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Factory\TBinaryProtocolFactory&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Factory\TBufferedTransportFactory&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Server\TServerSocket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Server\TSimpleServer&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//use Thrift\Server\TNonblockingServerSocket;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//use Thrift\Server\TNonblockingServer;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//use Thrift\Protocol\TBinaryProtocol;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//use Thrift\Transport\TPhpStream;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//use Thrift\Transport\TBufferedTransport;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;require_once&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;HelloWorldHandler.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$handler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Services\HelloWorld\HelloWorldHandler&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$processor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Services\HelloWorld\HelloWorldProcessor&lt;/span&gt;($handler);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$transportFactory &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TBufferedTransportFactory&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$protocolFactory &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TBinaryProtocolFactory&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//作为cli方式运行，监听端口，官方实现&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$transport &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TServerSocket&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9090&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TSimpleServer&lt;/span&gt;($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$server&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;serve&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//作为cli方式运行，非阻塞方式监听，基于libevent实现，非官方实现&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$transport = new TNonblockingServerSocket(&amp;#39;localhost&amp;#39;, 9090);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$server = new TNonblockingServer($processor, $transport, $transportFactory, $transportFactory, $protocolFactory, $protocolFactory);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$server-&amp;gt;serve();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//客户端和服务端在同一个输入输出流上&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//使用方式&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//1) cli 方式：php Client.php | php Server.php &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//2) cgi 方式：利用Apache或nginx监听http请求，调用php-fpm处理，将请求转换为PHP标准输入输出流&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$protocol = new TBinaryProtocol($transport, true, true);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$transport-&amp;gt;open();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$processor-&amp;gt;process($protocol, $protocol);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$transport-&amp;gt;close();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TException&lt;/span&gt; $tx) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;print&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;TException: &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$tx&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getMessage&lt;/span&gt;()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务端创建的步骤：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;首先初始化服务提供者handler&lt;/li&gt;&#10;&lt;li&gt;然后利用该handler初始化自动生成的processor&lt;/li&gt;&#10;&lt;li&gt;初始化数据传输方式transport&lt;/li&gt;&#10;&lt;li&gt;利用该传输方式初始化数据传输格式protocol&lt;/li&gt;&#10;&lt;li&gt;开始服务&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;编写客户端代码Client.php&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Services\HelloWorld&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;error_reporting&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;E_ALL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;THRIFT_ROOT&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/../../../&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;require_once&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;THRIFT_ROOT&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Thrift/ClassLoader/ThriftClassLoader.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\ClassLoader\ThriftClassLoader&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ThriftClassLoader&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;registerNamespace&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Thrift&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;THRIFT_ROOT&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;registerDefinition&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Service&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;THRIFT_ROOT&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/gen-php&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$loader&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;register&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//use Thrift\Transport\TPhpStream;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Protocol\TBinaryProtocol&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Transport\TSocket&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Transport\TBufferedTransport&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Thrift\Exception\TException&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//仅在与服务端处于同一输出输出流有用&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//使用方式：php Client.php | php Server.php &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//$transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//socket方式连接服务端&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//数据传输格式和数据传输方式与服务端一一对应&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//如果服务端以http方式提供服务，可以使用THttpClient/TCurlClient数据传输方式&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$transport &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TBufferedTransport&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TSocket&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9090&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$protocol &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TBinaryProtocol&lt;/span&gt;($transport);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Services\HelloWorld\HelloWorldClient&lt;/span&gt;($protocol);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$transport&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//同步方式进行交互&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$recv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $client&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sayHello&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Courages&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt; sayHello11dd:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$recv&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//异步方式进行交互&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$client&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send_sayHello&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Us&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt; send_sayHello &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$recv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $client&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;recv_sayHello&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt; recv_sayHello:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$recv&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$transport&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;TException&lt;/span&gt; $tx) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;print&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;TException: &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$tx&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getMessage&lt;/span&gt;()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端调用的步骤：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;初始化数据传输方式transport，与服务端对应&lt;/li&gt;&#10;&lt;li&gt;利用该传输方式初始化数据传输格式protocol，与服务端对应&lt;/li&gt;&#10;&lt;li&gt;实例化自动生成的Client对象&lt;/li&gt;&#10;&lt;li&gt;开始调用&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在终端上运行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#以cli方式运行TPhpStream &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#php Client.php | php Server.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#先运行Server.php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#要不然会报错：TException: TSocket: Could not connect to localhost:9090 (Connection refused [111])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php Server.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#在另外一个终端运行&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php Client.ph&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;官方给的例子，PHP作为服务端是以web方式进行提供的，在cli方式下并不能运行。&lt;/p&gt;&#10;&lt;p&gt;Thrift作为一个跨语言的服务框架，方便不同语言、模块之间互相调用，解耦服务逻辑代码，拓展了PHP的处理能力（如与Hbase交互），使得WEB架构更具弹性。与基于 SOAP 消息格式的 Web Service和基于 JSON 消息格式的 RESTful 服务不同，Thrif数据传输格式默认采用二进制传格式，对 XML 和 JSON 体积更小，但对于服务端的CPU占用比JSON、XML要高。PHP虽然有thrift_protocol扩展，但仅仅作为二进制数据传输格式化使用，其他文件的加载仍然为PHP，需要更多的开销。&lt;/p&gt;&#10;&lt;p&gt;如果由PHP来做为Thrift的服务端，仅仅这样子做仍然是不够的，Thrift仅仅实现的数据定义和传输，未实现RPC架构&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;需要避免重复加载各类文件，是否做成PHP扩展&lt;/li&gt;&#10;&lt;li&gt;数据传输格式和方式是否适需要自行扩展&lt;/li&gt;&#10;&lt;li&gt;客户端要能够自动连可使用的服务端，剔除失效的服务器&lt;/li&gt;&#10;&lt;li&gt;服务端需要处理客户端并发情况，是否多进程/异步处理&lt;/li&gt;&#10;&lt;li&gt;服务端需要监控服务是否正常&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;a class="link" href="http://www.workerman.net/workerman-thrift" target="_blank" rel="noopener"&#10; &gt;workerman-thrift-rpc&lt;/a&gt;对这些问题进行了解决，基于thrift提供了一个可靠性的RPC框架。对客户端和服务端的调用做了封装，提供统一入口，利用workerman做socket中转，当客户端发出请求时，将给socket转给服务端使用，提供服务。&lt;a class="link" href="http://www.workerman.net/workerman-jsonrpc" target="_blank" rel="noopener"&#10; &gt;workerman-json-rpc&lt;/a&gt;与workerman-thrift-rpc类似，采用异步（分步）收发，但简单多了，更像是一种约定。数据格式，发送时仅发送class，function，parameters三个参数，接收时，仅code，msg，data三个返回值，在格式约束及跨语言上，需要自行处理；不需要thrift那样依赖于生成器所生成的文件，客户端完全独立于服务端。&lt;/p&gt;&#10;&lt;p&gt;注：以上示例使用修改过的代码，附上代码：&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/06/thrift.zip" target="_blank" rel="noopener"&#10; &gt;thrift&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/" target="_blank" rel="noopener"&#10; &gt;Apache Thrift – 可伸缩的跨语言服务开发框架&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dongxicheng.org/search-engine/thrift-framework-intro/" target="_blank" rel="noopener"&#10; &gt;Thirft框架介绍&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://jnb.ociweb.com/jnb/jnbJun2009.html" target="_blank" rel="noopener"&#10; &gt;Apache Thrift&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://thrift.apache.org/docs/install/centos" target="_blank" rel="noopener"&#10; &gt;Building Apache Thrift on CentOS 6.5&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://thrift.apache.org/tutorial/php" target="_blank" rel="noopener"&#10; &gt;PHP Tutorial&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://willwarren.com/2012/01/24/creating-a-public-api-with-apache-thrift/" target="_blank" rel="noopener"&#10; &gt;Creating a public API with Apache Thrift&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://sites.google.com/site/waue0920/Home/hbase/hadoop-hbase-thrift-php-an-zhuang-she-ding-cheng-shi-she-ji" target="_blank" rel="noopener"&#10; &gt;hadoop + Hbase + thrift + php 安裝設定與程式設計&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ooso.net/archives/537" target="_blank" rel="noopener"&#10; &gt;php实现的thrift socket server&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.thrift.pl/Thrift-tutorial-our-own-hello-world.html" target="_blank" rel="noopener"&#10; &gt;Our own “Hello World!”&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 事件驱动开发</title><link>https://courages.us/php-%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/</link><pubDate>Fri, 26 Jun 2015 20:00:58 +0800</pubDate><guid>https://courages.us/php-%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/</guid><description>&lt;p&gt;最近在学习PHP的系统事件驱动（event-base）开发，发现PHP有好几个event扩展，根据底层库依赖分为两类：&lt;a class="link" href="http://libevent.org/" target="_blank" rel="noopener"&#10; &gt;libevent&lt;/a&gt;和&lt;a class="link" href="http://software.schmorp.de/pkg/libev.html" target="_blank" rel="noopener"&#10; &gt;libev&lt;/a&gt;。libevent可以为文件描述符、信号、超时设定等事件提供了监听回调，支持poll/kqueue/event port/select/epoll。libevent 库的其他组件提供其他功能，包括缓冲的事件系统（用于缓冲发送到客户端/从客户端接收的数据）以及 HTTP、DNS 和 RPC 系统的核心实现。libev提供了各种监听器，包括子进程监听，超时设定，定时器，IO监听，信号监听，文件监视等，支持epoll/kqueue/event ports/inotify/eventfd/signalfd，更快的时钟管理，时间变化检测和修正。PHP依赖libevent扩展有&lt;a class="link" href="http://php.net/manual/zh/intro.libevent.php" target="_blank" rel="noopener"&#10; &gt;libevent&lt;/a&gt;，&lt;a class="link" href="http://php.net/manual/zh/intro.event.php" target="_blank" rel="noopener"&#10; &gt;event&lt;/a&gt;，PHP依赖libev扩展则有&lt;a class="link" href="http://php.net/manual/zh/intro.ev.php" target="_blank" rel="noopener"&#10; &gt;Ev&lt;/a&gt;，&lt;a class="link" href="https://github.com/m4rw3r/php-libev" target="_blank" rel="noopener"&#10; &gt;libev&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;libevent在PHP事件驱动开发上应用广泛，比如&lt;a class="link" href="http://www.workerman.net/" target="_blank" rel="noopener"&#10; &gt;workerman&lt;/a&gt;，&lt;a class="link" href="http://daemon.io/" target="_blank" rel="noopener"&#10; &gt;phpDaemon&lt;/a&gt;，&lt;a class="link" href="http://reactphp.org/" target="_blank" rel="noopener"&#10; &gt;ReactPHP&lt;/a&gt;，&lt;a class="link" href="https://github.com/fhoenig/Kellner" target="_blank" rel="noopener"&#10; &gt;Kellner&lt;/a&gt;。CentOS上PHP 5.4安装libevent扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install libevent-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://pecl.php.net/get/libevent-0.1.0.tgz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -zxvf libevent-0.1.0.tgz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd libevent-0.1.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#增加libevent.so&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#是否安装成功&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php -m | grep libevent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;前面介绍过使用&lt;a class="link" href="https://courages.us/php-%e8%bf%9b%e7%a8%8b%e6%8e%a7%e5%88%b6pcntl/" target="_blank" rel="noopener"&#10; &gt;ticks和pcntl_signal&lt;/a&gt;来做定时器，然而tick运行机制是PHP解释器每执行 N 条可计时的低级语句就会发生的事件，如果tick值设置小了，会产生频繁的系统调用，设置大了又不能保证及时。使用libevent来设置一个定时器&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;print_dot&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Timer&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pEventBase;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pEvent;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; $nInterval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEventBase&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event_base_new&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;addEvent&lt;/span&gt;($p_pFunc, $p_mxArgs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEvent&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event_new&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;event_set&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEvent&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;EV_TIMEOUT&lt;/span&gt;, $p_pFunc, $p_mxArgs);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;event_base_set&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEvent&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEventBase&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;event_add&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEvent&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;nInterval&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;event_base_loop&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pEventBase&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pTimer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Timer&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pTimer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEvent&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;print_dot&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pTimer&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;loop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;libevent使用也很简单：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用event_base_new和event_new分别创建event_base和event&lt;/li&gt;&#10;&lt;li&gt;使用event_set为event设置要监听文件描述符fd，比如文件、socke、信号，超时则fd为0，事件类型和回调函数&lt;/li&gt;&#10;&lt;li&gt;使用event_base_set关联event_base和event&lt;/li&gt;&#10;&lt;li&gt;使用event_add将设置好的event加入事件监听器&lt;/li&gt;&#10;&lt;li&gt;调用event_base_loop开始处理事件&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;官网上有个&lt;a class="link" href="http://php.net/manual/zh/libevent.examples.php#99127" target="_blank" rel="noopener"&#10; &gt;例子&lt;/a&gt;用来做socket监听处理&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$socket &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_server&lt;/span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;tcp://0.0.0.0:2000&amp;#39;&lt;/span&gt;, $errno, $errstr);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;stream_set_blocking&lt;/span&gt;($socket, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event_base_new&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event_new&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;event_set&lt;/span&gt;($event, $socket, &lt;span style="color:#a6e22e"&gt;EV_READ&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EV_PERSIST&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;ev_accept&amp;#39;&lt;/span&gt;, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;event_base_set&lt;/span&gt;($event, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;event_add&lt;/span&gt;($event);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;event_base_loop&lt;/span&gt;($base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;connections&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;buffers&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ev_accept&lt;/span&gt;($socket, $flag, $base) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; $id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $connection &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stream_socket_accept&lt;/span&gt;($socket);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;stream_set_blocking&lt;/span&gt;($connection, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $id &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $buffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_new&lt;/span&gt;($connection, &lt;span style="color:#e6db74"&gt;&amp;#39;ev_read&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;ev_error&amp;#39;&lt;/span&gt;, $id);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_base_set&lt;/span&gt;($buffer, $base);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_timeout_set&lt;/span&gt;($buffer, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_watermark_set&lt;/span&gt;($buffer, &lt;span style="color:#a6e22e"&gt;EV_READ&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0xffffff&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_priority_set&lt;/span&gt;($buffer, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_enable&lt;/span&gt;($buffer, &lt;span style="color:#a6e22e"&gt;EV_READ&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EV_PERSIST&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// we need to save both buffer and connection outside&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;connections&amp;#39;&lt;/span&gt;][$id] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $connection;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;buffers&amp;#39;&lt;/span&gt;][$id] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $buffer;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ev_error&lt;/span&gt;($buffer, $error, $id) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_disable&lt;/span&gt;($GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;buffers&amp;#39;&lt;/span&gt;][$id], &lt;span style="color:#a6e22e"&gt;EV_READ&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EV_WRITE&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_free&lt;/span&gt;($GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;buffers&amp;#39;&lt;/span&gt;][$id]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;connections&amp;#39;&lt;/span&gt;][$id]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;buffers&amp;#39;&lt;/span&gt;][$id], $GLOBALS[&lt;span style="color:#e6db74"&gt;&amp;#39;connections&amp;#39;&lt;/span&gt;][$id]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ev_read&lt;/span&gt;($buffer, $id) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($read &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;event_buffer_read&lt;/span&gt;($buffer, &lt;span style="color:#ae81ff"&gt;256&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($read);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;相比libevent，event扩展提供了面向对象的方法，支持libevent 2+ 的特性，对HTTP，DNS，OpenSSL等协议操作进行封装。Kellner框架比较有意思，在PHP的libevent扩展基础上将http请求处理封装成了扩展，使用cli模式处理http请求，并给出了基于&lt;a class="link" href="http://framework.zend.com/" target="_blank" rel="noopener"&#10; &gt;Zend Framework 2&lt;/a&gt;的示例。&lt;/p&gt;&#10;&lt;p&gt;libev自称libevent的替代者，克服了libevent的一些不利影响，开销更小，Node JS便是利用它来做事件驱动。相比基于libeventd的扩展，基于libev的ev扩展更新比较积极，支持设置各种的监听器，为感兴趣的事件注册回调，比如文件变化，超时。CentOS上PHP 5.4安装ev扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://pecl.php.net/get/ev-0.2.15.tgz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -zxvf ev-0.2.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ev-0.2.15&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#增加ev.so&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#是否安装成功&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php -m | grep ev&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;libev封装了各种监视器，操作也比较简单。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 延迟1秒后执行，不重复&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pDelay &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvTimer&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;1 delay &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 每隔一秒执行一次的定时器，0秒后执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pTimer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvTimer&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;1 seconds &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 如果没有其他更高等级的监视器，那么就执行EvIdle，处于低优先级则不执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pIdle &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIdle&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;idle timer &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;},&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 每一次loop开始都会执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPrepare &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvPrepare&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;before timer &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;},&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 每一次loop都会执行，可以通过优先级调整执行顺序&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvCheck&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;after timer &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;},&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 定时器，每隔1.5秒后执行一次，0秒后开始&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pPeriod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvPeriodic&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0.&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1.5&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($w, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;(), &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * IO输入事件监听，可以拿去监听socket的Ev::WRITE和Ev::READ事件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pReadWatcher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvIo&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;STDIN&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;READ&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;STDIN is readable&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 注册监听感兴趣的信号&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pSignal &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvSignal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($watcher) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SIGTERM received&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$watcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;stop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 文件变化监听器，10秒监测一次&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pStatWatcher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvStat&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/var/log/messages&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($w) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/var/log/messages changed&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$attr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pStatWatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($attr[&lt;span style="color:#e6db74"&gt;&amp;#39;nlink&amp;#39;&lt;/span&gt;]) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Current size: %ld&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $attr[&lt;span style="color:#e6db74"&gt;&amp;#39;size&amp;#39;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Current atime: %ld&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $attr[&lt;span style="color:#e6db74"&gt;&amp;#39;atime&amp;#39;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Current mtime: %ld&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $attr[&lt;span style="color:#e6db74"&gt;&amp;#39;mtime&amp;#39;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;fprintf&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;STDERR&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;`messages` file is not there!&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pStatWatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;stop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 开始执行Ev::RUN_ONCE则立即执行Ev::RUN_NOWAIT则非阻塞执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以监听子进程&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fprintf&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;STDERR&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;pcntl_fork failed&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;elseif&lt;/span&gt; ($pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $w &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EvChild&lt;/span&gt;($pid, &lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; ($w, $revents) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $w&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;stop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Process %d exited with status %d&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $w&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rpid&lt;/span&gt;, $w&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rstatus&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Ev&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Protect against Zombies&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_wait&lt;/span&gt;($status);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Forked child&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;php的libev扩展也实现了libev的所有监视器，提供类似的用法，但比较久没更新了。&lt;/p&gt;&#10;&lt;p&gt;在网络编程中，使用事件驱动模型监听感兴趣的事件，结合异步处理，能够大大提高服务器性能。传统服务器模型如Apache为每一个请求生成一个子进程。当用户连接到服务器的一个子进程就产生，并处理连接。每个连接获得一个单独的线程和子进程。当用户请求数据返回时，子进程开始等待数据库操作返回。如果此时另一个用户也请求返回数据，这时就产生了阻塞。以下引用自&lt;a class="link" href="http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/" target="_blank" rel="noopener"&#10; &gt;《使用事件驱动模型实现高效稳定的网络服务器程序》&lt;/a&gt;&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;简单网络编程模型里面，服务器与客户端都是一应一答，大部分的 socket 接口都是阻塞型的。在面对多个客户端的请求时候，最简单的解决方式是在服务器端使用多线程（或多进程）。如果要同时响应成百上千路的连接请求，则无论多线程还是多进程都会严重占据系统资源，降低系统对外界响应效率，而线程与进程本身也更容易进入假死状态。&lt;br&gt;&#10;于是便有了“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率，其维持一定合理数量的线程，并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池，尽量重用已有的连接、减少创建和关闭连接的频率。&lt;br&gt;&#10;但是，“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用 IO 接口带来的资源占用。而且，所谓“池”始终有其上限，当请求大大超过上限时，“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模，并根据响应规模调整“池”的大小。对付可能同时出现的上千甚至上万次的客户端请求，“线程池”或“连接池”或许可以缓解部分压力，但是不能解决所有问题。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;于是便有了基于事件驱动的非阻塞型服务器，比如Nginx，Node.js。Nginx采用事件驱动，使用epoll事件模型，充分使用异步逻辑，削减了上下文调度开销，并发服务能力更强。Node.js 的异步机制是基于事件的，所有的磁盘 I/O、网络通信、数据库查询都以非阻塞的方式请求，返回的结果由事件循环来处理。Node.js 在执行的过程中会维护一个事件队列，程序在执行时进入事件循环等待下一个事件到来，每个异步式 I/O 请求完成后会被推送到事件队列，等待程序进程进行处理。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod" target="_blank" rel="noopener"&#10; &gt;libev – a high performance full-featured event loop written in C&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.wangafu.net/~nickm/libevent-book/Ref4_event.html" target="_blank" rel="noopener"&#10; &gt;Working with events&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ibm.com/developerworks/cn/aix/library/au-libev/" target="_blank" rel="noopener"&#10; &gt;使用 libevent 和 libev 提高网络应用性能&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://gist.github.com/jcouyang/9914091" target="_blank" rel="noopener"&#10; &gt;为什么事件驱动服务器这么火&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/SteveRhoades2/asynchronous-php-and-realtime-messaging" target="_blank" rel="noopener"&#10; &gt;Asynchronous PHP and Real-time Messaging&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://jingxin.me/blog/blog/2013/03/05/react-dot-php-zhong-de-yi-bu-shi-xian/" target="_blank" rel="noopener"&#10; &gt;react.php 中的异步实现&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP ZooKeeper分布式应用开发</title><link>https://courages.us/php-zookeeper%E5%88%86%E5%B8%83%E5%BC%8F%E6%9C%8D%E5%8A%A1%E5%BC%80%E5%8F%91/</link><pubDate>Wed, 24 Jun 2015 09:58:29 +0800</pubDate><guid>https://courages.us/php-zookeeper%E5%88%86%E5%B8%83%E5%BC%8F%E6%9C%8D%E5%8A%A1%E5%BC%80%E5%8F%91/</guid><description>&lt;p&gt;&lt;a class="link" href="https://zookeeper.apache.org/" target="_blank" rel="noopener"&#10; &gt;ZooKeeper&lt;/a&gt;是一个中心化服务，用于分布式应用下的配置同步和协调，提供统一配置服务，统一命名服务，分布式同步，集群管理等。Zookeeper 从设计模式角度来看，是一个基于观察者模式设计的分布式服务管理框架，它负责存储和管理大家都关心的数据，然后接受观察者的注册，一旦这些数据的状态发生变化，Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应。ZooKeeper的应用场景包括：统一命名服务；配置管理；集群管理；队列管理等。&lt;/p&gt;&#10;&lt;p&gt;ZooKeeper作为一个Java应用程序，有大神开发了PHP的扩展：&lt;a class="link" href="https://github.com/andreiz/php-zookeeper" target="_blank" rel="noopener"&#10; &gt;php-zookeeper&lt;/a&gt;。利用ZooKeeper，我们可以让分布式的PHP应用程序协调产生leader，为woker分配任务，当leader崩溃时，自动选举产生leader；也可以作分布式的锁和队列。&lt;/p&gt;&#10;&lt;p&gt;ZooKeeper本身是一个集群，至少需要表示3台，只要超过半数节点正常就可以工作，避免单点故障。首先需要安装JDK环境&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;yum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;search&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;java&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;grep&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;java-&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sudo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;yum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;java&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1.8&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;openjdk&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;devel&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装ZooKeeper，从官网下载&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar zxfv zookeeper-3.4.6.tar.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd zookeeper-3.4.6/src/c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#创建libzookeeper.conf，内容为/usr/lib，以便编译扩展使用&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/ld.so.conf.d/libzookeeper.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使配置生效&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ldconfig&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后安装PHP的扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/andreiz/php-zookeeper.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd php-zookeeper&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改php.ini配置，增加以下内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[zookeeper]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension = zookeeper.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看是否加载成功&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php -m | grep zookeeper&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改ZooKeeper配置，可以改变里面的DataDir熟悉，默认在/tmp下面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp conf/zoo_sample.cfg conf/zoo.cfg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim conf/zoo.cfg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后终端A里面运行ZooKeeper，通过shell进行交互&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd zookeeper-3.4.6/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./zkServer.sh start&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./zkCli.sh -server 127.0.0.1:2181&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;create /test hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;Created /test&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls /&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;test, zookeeper&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时便已成功连到了ZooKeeper，并创建了一个名为“/test”的znode。ZooKeeper以树形结构保存数据。这很类似于文件系统，但“文件夹”又和文件很像。znode是ZooKeeper保存的实体。&lt;/p&gt;&#10;&lt;p&gt;新建一个PHP脚本来测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZookeeperDemo&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;watcher&lt;/span&gt;( $i, $type, $key ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Insider Watcher&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Watcher gets consumed so we need to set a new one&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#39;/test&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($this, &lt;span style="color:#e6db74"&gt;&amp;#39;watcher&amp;#39;&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$zoo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZookeeperDemo&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1:2181&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$zoo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#39;/test&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($zoo, &lt;span style="color:#e6db74"&gt;&amp;#39;watcher&amp;#39;&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在新的终端B里面运行这个脚本&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ php zookeeperdemo1.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;返回刚才的那个终端A里面，改变节点“/test”存储的数据&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set /test world&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候在终端B里面变化打印“Insider Watcher”。注意：这里注册的回到函数仅支持对象的方法，不支持普通的函数。&lt;/p&gt;&#10;&lt;p&gt;前面说过，ZooKeeper是一个基于观察者模式设计的分布式服务管理框架。Zookeeper提供了绑定在znode上的监听器，一旦监听到znode数据发生变化，便会通知所有注册的客户端。所以也可以应用于发布订阅模式。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="http://systemsarchitect.net/distributed-application-in-php-with-apache-zookeeper/" target="_blank" rel="noopener"&#10; &gt;这篇文章&lt;/a&gt;还举例，如何让多个PHP脚本自动选举leader，分配工作。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Worker&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CONTAINER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/cluster&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $acl &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;perms&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PERM_ALL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;scheme&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;anyone&amp;#39;&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $isLeader &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $znode;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;( $host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;, $watcher_cb &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, $recv_timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;parent&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;( $host, $watcher_cb, $recv_timeout );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;register&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( &lt;span style="color:#f92672"&gt;!&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt; ) ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;acl&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Zookeeper::EPHEMERAL - auto remove if client session goes away&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Zookeeper::EPHEMERAL - auto increasing sequence number&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/w-&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;acl&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EPHEMERAL&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zookeeper&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SEQUENCE&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str_replace&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;I&amp;#39;m registred as: %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $watching &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;watchPrevious&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $watching &lt;span style="color:#f92672"&gt;==&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;Nobody here, I&amp;#39;m the leader&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setLeader&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;I&amp;#39;m watching %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $watching );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;watchPrevious&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $workers &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getChildren&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sort&lt;/span&gt;( $workers );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sizeof&lt;/span&gt;( $workers );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;( $i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $size ; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; $workers[ $i ] ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $i &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//for node path change event&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $workers[ $i &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ], &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;( $this, &lt;span style="color:#e6db74"&gt;&amp;#39;watchNode&amp;#39;&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//for node path exist event&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $workers[ $i &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ], &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;( $this, &lt;span style="color:#e6db74"&gt;&amp;#39;watchNode&amp;#39;&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $workers[ $i &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $workers[ $i ];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;sprintf&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;Something went very wrong! I can&amp;#39;t find myself: %s/%s&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;CONTAINER&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; ) );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;watchNode&lt;/span&gt;( $i, $type, $name ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $watching &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;watchPrevious&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $watching &lt;span style="color:#f92672"&gt;==&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;znode&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;I&amp;#39;m the new leader!&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setLeader&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;Now I&amp;#39;m watching %s&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, $watching );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;isLeader&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isLeader&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setLeader&lt;/span&gt;($flag) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isLeader&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $flag;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;register&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isLeader&lt;/span&gt;() ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;doLeaderJob&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;doWorkerJob&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;( &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;doLeaderJob&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Leading&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;doWorkerJob&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Working&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//host can be multiple, e.g &amp;#39;127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183&amp;#39; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$worker &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Worker&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1:2181&amp;#39;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$worker&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开多个终端运行这个脚本。使用Ctrl+c或其他方法退出第一个脚本。刚开始不会有任何变化，worker可以继续工作。后来，ZooKeeper会发现超时，并选举出新的leader。&lt;/p&gt;&#10;&lt;p&gt;除此之外，利用这个扩展还可以实现一下其他的应用场景，比如排他锁和共享锁：&lt;a class="link" href="https://github.com/Gutza/php-zookeeper-recipes" target="_blank" rel="noopener"&#10; &gt;php-zookeeper-recipes&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://systemsarchitect.net/distributed-application-in-php-with-apache-zookeeper/" target="_blank" rel="noopener"&#10; &gt;Distributed application in PHP with Apache Zookeeper&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/" target="_blank" rel="noopener"&#10; &gt;分布式服务框架 Zookeeper — 管理分布式环境中的数据&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://anykoro.sinaapp.com/2013/04/05/%E4%BD%BF%E7%94%A8apache-zookeeper%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2php%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/" target="_blank" rel="noopener"&#10; &gt;使用Apache Zookeeper分布式部署PHP应用程序&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.biaodianfu.com/zookeeper.html" target="_blank" rel="noopener"&#10; &gt;分布式服务框架：Zookeeper&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 进程间通信</title><link>https://courages.us/php-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/</link><pubDate>Tue, 23 Jun 2015 10:54:59 +0800</pubDate><guid>https://courages.us/php-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/</guid><description>&lt;p&gt;上一篇介绍了&lt;a class="link" href="https://courages.us/php-%e8%bf%9b%e7%a8%8b%e6%8e%a7%e5%88%b6pcntl/" target="_blank" rel="noopener"&#10; &gt;PHP的多进程开发&lt;/a&gt;，进程间通过信号进行交互。这里介绍一下PHP的进程间通信（IPC）方法，包括基于System V IPC通信，如信号量、进程间消息、共享内存和基于socket的IPC通信。&lt;/p&gt;&#10;&lt;p&gt;信号量主要作为不同进程以及同一进程不同线程之间的同步手段。信号量是一个特殊的变量，程序对其访问都是原子操作，且只允许对它进行等待和发送信息操作。如果信号量是一个任意的整数，通常被称为计数信号量，或一般信号量；如果信号量只有二进制的0或1，称为二进制信号量。在linux系中，二进制信号量又称&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E4%BA%92%E6%96%A5%E9%94%81" target="_blank" rel="noopener"&#10; &gt;Mutex，互斥锁&lt;/a&gt;。以下例子采用信号量来协调进程对资源的访问&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ftok&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;s&amp;#39;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 同时最多只能有一个进程进入临界区&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sem_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sem_get&lt;/span&gt; ( $key, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;This is a room，can only stay one people!&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n\r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 派生子进程&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt; ();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt; ( &lt;span style="color:#e6db74"&gt;&amp;#39;fork failed!&amp;#39;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;parent&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;child&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; want to enter the room &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sem_acquire&lt;/span&gt; ( $sem_id );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 原子操作开始&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; in the room , other people can&amp;#39;t enter!&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt; ( &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; leave the room&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 原子操作结束&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sem_release&lt;/span&gt; ( $sem_id );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_waitpid&lt;/span&gt; ( $pid, $status );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;sem_remove&lt;/span&gt; ( $sem_id ); &lt;span style="color:#75715e"&gt;// 移除信号量&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;sem_get和sem_remove分别为创建和销毁信号量。当前进程（父进程）通过sem_acquire获取到信号量后其他进程（子进程）将会一直阻塞直到获取到信号量；在sem_acquire和sem_release之间操作都将是原子性的；当前进程通过sem_release释放所请求的信号量，其他进程便使用，从而实现对资源的有序访问。sem_acquire是阻塞操作，即之后的程序都需要等待获取到信号量后才能继续执行。使用多个信号量控制，需要注意是否会造成死锁。&lt;/p&gt;&#10;&lt;p&gt;消息队列提供了一种从一个进程向另一个进程异步发送一个数据块的方法，消息的发送者和接收者不需要同时与消息队列互交。消息会保存在队列中，直到接收者取回它。有足够权限的进程可以向队列中添加消息，被赋予读权限的进程则可以读走队列中的消息。以下是PHP子进程使用消息队列与父进程进行通信&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 生成key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$message_queue_key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ftok&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 根据生成的key新建队列，也可自定，如123456&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$message_queue &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;msg_get_queue&lt;/span&gt; ( $message_queue_key, &lt;span style="color:#ae81ff"&gt;0666&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pids &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt; ();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// 创建子进程&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pids [$i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt; ();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pids [$i]) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;No.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$i&lt;/span&gt;&lt;span style="color:#e6db74"&gt; child process was created, the pid is &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$pids[$i]&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_wait&lt;/span&gt; ( $status ); &lt;span style="color:#75715e"&gt;// 非阻塞的线程等待,防止僵尸进程的出现&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;} &lt;span style="color:#66d9ef"&gt;elseif&lt;/span&gt; ($pids [$i] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posix_getpid&lt;/span&gt; ();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;process.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$pid&lt;/span&gt;&lt;span style="color:#e6db74"&gt; is writing now&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;// 写队列&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;msg_send&lt;/span&gt; ( $message_queue, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;this is process.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$pid&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;s data&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;posix_kill&lt;/span&gt; ( $pid, &lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// 读队列&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;msg_receive&lt;/span&gt; ( $message_queue, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $message_type, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;, $message, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;MSG_IPC_NOWAIT&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $message;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// 获取队列内消息数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;msg_stat_queue&lt;/span&gt; ( $message_queue );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($a [&lt;span style="color:#e6db74"&gt;&amp;#39;msg_qnum&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ( &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;消息队列存在消息大小及队列长度的限制，一旦超过将写不进去。&lt;/p&gt;&#10;&lt;p&gt;共享内存使得多个进程可以访问同一块内存空间，是最快的可用IPC形式。一个进程在内存创建了一个共享区域，其他进程也可以对这块内存区域进行访问&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//Check the command line arguments&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sizeof&lt;/span&gt;($argv) &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Usage: php shared_memory.php &amp;lt;send|get|delete&amp;gt; &amp;lt;integer identifier&amp;gt; &amp;lt;value&amp;gt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//Define shared memory segment properties.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;987654&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$permissions &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0666&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//Create or open the shared memory segment.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$segment &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shm_attach&lt;/span&gt;($key, $size, $permissions);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//Handle operations for the segment.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt;($argv[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;send&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;shm_put_var&lt;/span&gt;($segment, $argv[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;], $argv[&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Message sent to shared memory segment.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;get&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shm_get_var&lt;/span&gt;($segment, $argv[&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Received data: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$data&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;delete&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;shm_remove&lt;/span&gt;($segment);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Shared memory segment released.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;共享内存并未提供同步机制，往往与其它通信机制，如信号量结合使用，来达到进程间的同步及互斥。PHP还有另外一个共享内存扩展：&lt;a class="link" href="http://php.net/manual/zh/book.shmop.php" target="_blank" rel="noopener"&#10; &gt;shmop&lt;/a&gt;。注意，共享内存存在内存限制。&lt;/p&gt;&#10;&lt;p&gt;Sockets IPC提供了进程间双向的点对点通信。通过&lt;a class="link" href="http://php.net/manual/zh/function.socket-create-pair.php" target="_blank" rel="noopener"&#10; &gt;socket_create_pair&lt;/a&gt;创建一对socket，作为上行和下行，父进程和子进程分别使用其中一个进行读写通信&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sockets &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Message From Parent.&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strtwo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Message From Child.&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_create_pair&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;AF_UNIX&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SOCK_STREAM&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $sockets) &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;socket_create_pair() failed. Reason: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_strerror&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;socket_last_error&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Could not fork Process.&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;elseif&lt;/span&gt; ($pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/*parent*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_write&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], $strone, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($strone)) &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;socket_write() failed. Reason: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_strerror&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;socket_last_error&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_read&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($strtwo), &lt;span style="color:#a6e22e"&gt;PHP_BINARY_READ&lt;/span&gt;) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; $strtwo) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Recieved &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$strtwo&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/*child*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_write&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], $strtwo, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($strtwo)) &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;socket_write() failed. Reason: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_strerror&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;socket_last_error&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_read&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($strone), &lt;span style="color:#a6e22e"&gt;PHP_BINARY_READ&lt;/span&gt;) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; $strone) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Recieved &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$strone&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($sockets[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下例子是&lt;a class="link" href="https://github.com/lifo101/php-ipc" target="_blank" rel="noopener"&#10; &gt;github&lt;/a&gt;上一个利用PHP Sockets IP开发的多进程任务处理&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Lifo\IPC&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ticks&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessInterface&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;($parent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessPoolException&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessPool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var Integer Maximum workers allowed at once */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $max;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var boolean If true workers will fork. Otherwise they will run synchronously */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $fork;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var Integer Total results collected */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $count;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var array Pending processes that have not been started yet */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $pending;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var array Processes that have been started */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $workers;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var array Results that have been collected */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $results;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var \Closure Function to call every time a child is forked */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $createCallback;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var array children PID&amp;#39;s that died prematurely */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $caught;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/** @var boolean Is the signal handler initialized? */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $initialized;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; $instance &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($max &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, $fork &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$pid = getmypid();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//if (isset(self::$instance[$pid])) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// $caller = debug_backtrace();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// throw new ProcessPoolException(&amp;#34;Cannot instantiate more than 1 ProcessPool in the same process in {$caller[0][&amp;#39;file&amp;#39;]} line {$caller[0][&amp;#39;line&amp;#39;]}&amp;#34;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//self::$instance[$pid] = $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $max;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fork&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $fork;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;caught&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;initialized&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// make sure signal handler is removed&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;uninit&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//unset(self::$instance[getmygid()]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Initialize the signal handler.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Note: This will replace any current handler for SIGCHLD.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param boolean $force Force initialization even if already initialized&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;init&lt;/span&gt;($force &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;initialized&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;$force) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;initialized&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGCHLD&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($this, &lt;span style="color:#e6db74"&gt;&amp;#39;signalHandler&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;uninit&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;initialized&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;initialized&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGCHLD&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;SIG_DFL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;signalHandler&lt;/span&gt;($signo)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; ($signo) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGCHLD&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;reaper&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Reap any dead children&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;reaper&lt;/span&gt;($pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, $status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_waitpid&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, $status, &lt;span style="color:#a6e22e"&gt;WNOHANG&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;[$pid])) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// @todo does the socket really need to be closed?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//@socket_close($this-&amp;gt;workers[$pid][&amp;#39;socket&amp;#39;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;[$pid]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// the child died before the parent could initialize the $worker&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// queue. So we track it temporarily so we can handle it in&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// self::create().&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;caught&lt;/span&gt;[$pid] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $status;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_waitpid&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, $status, &lt;span style="color:#a6e22e"&gt;WNOHANG&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Wait for any child to be ready&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param integer $timeout Timeout to wait (fractional seconds)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return array|null Returns array of sockets ready to be READ or null&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wait&lt;/span&gt;($timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// trash var needed for socket_select&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $startTime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// maintain worker queue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// check each child socket pair for a new result&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $read &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_map&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;($w){ &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $w[&lt;span style="color:#e6db74"&gt;&amp;#39;socket&amp;#39;&lt;/span&gt;]; }, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// it&amp;#39;s possible for no workers/sockets to be present due to REAPING&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($read)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $ok &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_select&lt;/span&gt;($read, $x, $x, $timeout);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($ok &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; $ok &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $read;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// timed out?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($timeout &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $startTime &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; $timeout) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// no sense in waiting if we have no workers and no more pending&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Return the next available result.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Blocks unless a $timeout is specified.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param integer $timeout Timeout in fractional seconds if no results are available.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return mixed Returns next child response or null on timeout&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @throws ProcessPoolException On timeout if $nullOnTimeout is false&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;($timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, $nullOnTimeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $startTime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getPending&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// return the next result&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hasResult&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getResult&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// wait for the next result&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $ready &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;wait&lt;/span&gt;($timeout);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;is_array&lt;/span&gt;($ready)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($ready &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $socket) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_fetch&lt;/span&gt;($socket);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($res &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt;[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $res;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hasResult&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getResult&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// timed out?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($timeout &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $startTime &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; $timeout) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($nullOnTimeout) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessPoolException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Timeout&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Return results from all workers.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Does not return until all pending workers are complete or the $timeout&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * is reached.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param integer $timeout Timeout in fractional seconds if no results are available.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return array Returns an array of results&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @throws ProcessPoolException On timeout if $nullOnTimeout is false&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getAll&lt;/span&gt;($timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, $nullOnTimeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $results &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $startTime &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getPending&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;($timeout);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($res &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $results[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $res;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;ProcessPoolException&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// timed out&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// timed out?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($timeout &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $startTime &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; $timeout) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($nullOnTimeout) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessPoolException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Timeout&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $results;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hasResult&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Return the next available result or null if none are available.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * This does not wait or manage the worker queue.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getResult&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_shift&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Apply a worker to the working or pending queue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param Callable $func Callback function to fork into.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return ProcessPool&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;($func &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// add new function to pending queue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($func &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($func &lt;span style="color:#a6e22e"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\Closure&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; $func &lt;span style="color:#a6e22e"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessInterface&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_callable&lt;/span&gt;($func)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;func_get_args&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\UnexpectedValueException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Parameter 1 in ProcessPool#apply must be a Closure or callable&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// start a new worker if our current worker queue is low&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;) &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;call_user_func_array&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($this, &lt;span style="color:#e6db74"&gt;&amp;#39;create&amp;#39;&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;array_shift&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Create a new worker.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * If forking is disabled this will BLOCK.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param Closure $func Callback function.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param mixed Any extra parameters are passed to the callback function.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @throws \RuntimeException if the child can not be forked.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;($func &lt;span style="color:#75715e"&gt;/*, ...*/&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// create a socket pair before forking so our child process can write to the PARENT.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $sockets &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strtoupper&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;substr&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;PHP_OS&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;WIN&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AF_INET&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AF_UNIX&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;socket_create_pair&lt;/span&gt;($domain, &lt;span style="color:#a6e22e"&gt;SOCK_STREAM&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $sockets) &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\RuntimeException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;socket_create_pair failed: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_strerror&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;socket_last_error&lt;/span&gt;()));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;list&lt;/span&gt;($child, $parent) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $sockets; &lt;span style="color:#75715e"&gt;// just to make the code below more readable&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($sockets);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_merge&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($parent), &lt;span style="color:#a6e22e"&gt;array_slice&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;func_get_args&lt;/span&gt;(), &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;init&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// make sure signal handler is installed&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fork&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\RuntimeException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Could not fork&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// PARENT PROCESS; Just track the child and return&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($parent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;[$pid] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pid&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $pid,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;socket&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $child,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// don&amp;#39;t pass $parent to callback&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;doOnCreate&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;array_slice&lt;/span&gt;($args, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// If a SIGCHLD was already caught at this point we need to&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// manually handle it to avoid a defunct process.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;isset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;caught&lt;/span&gt;[$pid])) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;reaper&lt;/span&gt;($pid, $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;caught&lt;/span&gt;[$pid]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;caught&lt;/span&gt;[$pid]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// CHILD PROCESS; execute the callback function and wait for response&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;socket_close&lt;/span&gt;($child);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($func &lt;span style="color:#a6e22e"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessInterface&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;call_user_func_array&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($func, &lt;span style="color:#e6db74"&gt;&amp;#39;run&amp;#39;&lt;/span&gt;), $args);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;call_user_func_array&lt;/span&gt;($func, $args);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($result &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_send&lt;/span&gt;($parent, $result);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// this is kind of useless in a forking context but at&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// least the developer can see the exception if it occurs.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; $e;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// forking is disabled so we simply run the child worker and wait&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// synchronously for response.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($func &lt;span style="color:#a6e22e"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessInterface&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;call_user_func_array&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($func, &lt;span style="color:#e6db74"&gt;&amp;#39;run&amp;#39;&lt;/span&gt;), $args);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;call_user_func_array&lt;/span&gt;($func, $args);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($result &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$this-&amp;gt;results[] = $result;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_send&lt;/span&gt;($parent, $result);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// read anything pending from the worker if they chose to write&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// to the socket instead of just returning a value.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $read &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;($child);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $ok &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_select&lt;/span&gt;($read, $x, $x, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($ok &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;and&lt;/span&gt; $ok &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;socket_fetch&lt;/span&gt;($read[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($res &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt;[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $res;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($ok);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;\Exception&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// nop; we didn&amp;#39;t fork so let the caller handle it&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; $e;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Clear all pending workers from the queue.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clear&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Send a SIGTERM (or other) signal to the PID given&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kill&lt;/span&gt;($pid, $signo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;posix_kill&lt;/span&gt;($pid, $signo);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Send a SIGTERM (or other) signal to all current workers&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;killAll&lt;/span&gt;($signo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $w) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;kill&lt;/span&gt;($w[&lt;span style="color:#e6db74"&gt;&amp;#39;pid&amp;#39;&lt;/span&gt;], $signo);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Set a callback when a new forked process is created. This will allow the&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * parent to perform some sort of cleanup after every child is created.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * This is useful to reinitialize certain resources like DB connections&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * since children will inherit the parent resources.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param \Closure $callback Function to callback after every forked child.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setOnCreate&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;\Closure&lt;/span&gt; $callback &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;createCallback&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $callback;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;doOnCreate&lt;/span&gt;($args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;())&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;createCallback&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;call_user_func_array&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;createCallback&lt;/span&gt;, $args);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Return the total jobs that have NOT completed yet.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getPending&lt;/span&gt;($pendingOnly &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pendingOnly) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;results&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getWorkers&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getActive&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pending&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;workers&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getCompleted&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setForking&lt;/span&gt;($fork)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fork&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $fork;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setMax&lt;/span&gt;($max)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;is_numeric&lt;/span&gt;($max) &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; $max &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;\InvalidArgumentException&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Max value must be &amp;gt; 0&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $max;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getMax&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Write the data to the socket in a predetermined format&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_send&lt;/span&gt;($socket, $data)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $serialized &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;serialize&lt;/span&gt;($data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $hdr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;N&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($serialized)); &lt;span style="color:#75715e"&gt;// 4 byte length&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $buffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $hdr &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $serialized;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $total &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($buffer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $sent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_write&lt;/span&gt;($socket, $buffer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($sent &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// @todo handle error?&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$error = socket_strerror(socket_last_error());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($sent &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; $total) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $total &lt;span style="color:#f92672"&gt;-=&lt;/span&gt; $sent;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $buffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;substr&lt;/span&gt;($buffer, $sent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Read a data packet from the socket in a predetermined format.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Blocking.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_fetch&lt;/span&gt;($socket)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// read 4 byte length first&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $hdr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $read &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_read&lt;/span&gt;($socket, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($hdr));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($read &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; $read &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $hdr &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $read;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($hdr) &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;list&lt;/span&gt;($len) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_values&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;unpack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;N&amp;#34;&lt;/span&gt;, $hdr));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// read the full buffer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $buffer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $read &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;socket_read&lt;/span&gt;($socket, $len &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($buffer));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($read &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; $read &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $buffer &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $read;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($buffer) &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $len);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;unserialize&lt;/span&gt;($buffer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $data;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pool &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProcessPool&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; $i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pool&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;apply&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;($parent) &lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; ($i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$i&lt;/span&gt;&lt;span style="color:#e6db74"&gt; running...&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;mt_srand&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// must re-seed for each child&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$rand &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mt_rand&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2000000&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;usleep&lt;/span&gt;($rand);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $i &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; : slept for &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; ($rand &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; seconds&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; ($pool&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getPending&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pool&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// timeout in 1 second&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;GOT: &amp;#34;&lt;/span&gt;, $result, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;} &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;ProcessPoolException&lt;/span&gt; $e) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;// timeout&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当前进程（父进程）添加任务时交由其他进程（子进程）处理，不阻塞当前进程；其他进程运行结束后，通过socket返回结果给父进程。&lt;/p&gt;&#10;&lt;p&gt;当然进程间通信也可以通过文件（FIFO）或者类似的中介角色如异步消息队列，Mysql，Redis等等进行交互。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/book.sem.php" target="_blank" rel="noopener"&#10; &gt;Semaphore, Shared Memory and IPC&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ibm.com/developerworks/cn/linux/l-ipc/" target="_blank" rel="noopener"&#10; &gt;深刻理解Linux进程间通信（IPC）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.phpclasses.org/blog/post/276-PHP-IPC-with-Daemon-Service-using-Message-Queues-Shared-Memory-and-Semaphores.html" target="_blank" rel="noopener"&#10; &gt;PHP IPC with Daemon Service using Message Queues, Shared Memory and Semaphores&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2008/04/21/101.html" target="_blank" rel="noopener"&#10; &gt;关于PHP你可能不知道的－PHP的事件驱动化设计&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ibm.com/developerworks/library/os-php-shared-memory/" target="_blank" rel="noopener"&#10; &gt;Store datasets directly in shared memory with PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.re-cycledair.com/php-dark-arts-shared-memory-segments-ipc" target="_blank" rel="noopener"&#10; &gt;PHP Dark Arts: Shared Memory Segments (IPC)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.workingsoftware.com.au/page/Something_Like_Threading" target="_blank" rel="noopener"&#10; &gt;Something Like Threading – PHP Process Forking and Interprocess Communication&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://demonastery.org/2011/04/mimicking-threading-in-php/" target="_blank" rel="noopener"&#10; &gt;Mimicking Threading in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/huyanping/article/details/38758665" target="_blank" rel="noopener"&#10; &gt;基于System V Message queue的PHP消息队列封装&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/huyanping/article/details/38758665" target="_blank" rel="noopener"&#10; &gt;PHP进程间通信System V消息队列&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.haiyun.me/archives/927.html" target="_blank" rel="noopener"&#10; &gt;PHP进程间通信System V信号量&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://sysmagazine.com/posts/210228/" target="_blank" rel="noopener"&#10; &gt;we Do web sockets on PHP from null. A part 2. IPC&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/en/function.proc-open.php" target="_blank" rel="noopener"&#10; &gt;proc_open&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 进程控制PCNTL</title><link>https://courages.us/php-%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6pcntl/</link><pubDate>Thu, 18 Jun 2015 20:01:11 +0800</pubDate><guid>https://courages.us/php-%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6pcntl/</guid><description>&lt;p&gt;PHP的进程控制PCNTL支持实现了Unix方式的进程创建, 程序执行，信号处理以及进程的中断。 PCNTL只支持linux平台下cli模式，不支持Windows平台，也不能被应用在Web服务器环境（cgi等），当其被用于Web服务环境时可能会带来意外的结果。通常，PCNTL会结合另外一个扩展来使用&lt;a class="link" href="http://php.net/manual/zh/ref.posix.php" target="_blank" rel="noopener"&#10; &gt;POSIX&lt;/a&gt;来开发（也不支持Windows平台）。&lt;/p&gt;&#10;&lt;p&gt;pcntl_fork可以创建一个子进程，父进程和子进程 都从fork的位置开始向下继续执行。创建成功时，父进程得到的返回值是子进程号而子进程得到的返回值是0；创建失败时，父进程得到返回值是-1，不会创建子进程，并触发一个PHP错误。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//父进程和子进程都会执行下面代码&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//错误处理：创建子进程失败时返回-1.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;could not fork&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//父进程会得到子进程号，所以这里是父进程执行的逻辑&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_wait&lt;/span&gt;($status); &lt;span style="color:#75715e"&gt;//等待子进程中断，防止子进程成为僵尸进程。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在对应的父进程结束执行后，子进程就会变成孤儿进程，但之后会立即由init进程（进程ID为1）“收养”为其子进程。&lt;/p&gt;&#10;&lt;p&gt;某一子进程终止执行后，若其父进程未提前调用wait，则内核会持续保留子进程的退出状态等信息，以使父进程可以wait获取之[2] 。而因为在这种情况下，子进程虽已终止，但仍在消耗系统资源，所以其亦称僵尸进程。wait常于SIGCHLD信号的处理函数中调用。&lt;/p&gt;&#10;&lt;p&gt;为避免产生僵尸进程，一般采取的方式是：将父进程中对SIGCHLD信号的处理函数设为SIG_IGN（忽略信号）；fork两次并杀死一级子进程，令二级子进程成为孤儿进程而被init所“收养”、清理。&lt;/p&gt;&#10;&lt;p&gt;采用二次创建子进程的方式&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//创建成功，在父进程中执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;run in parent process&amp;#34;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//pcntl_wait($status);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//创建失败，在父进程中处理&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Couldn&amp;#39;t create child process.&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//创建成功，在子进程中执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//再次创建子进程，即孙进程&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//在孙进程中执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posix_setsid&lt;/span&gt;())&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; &lt;span style="color:#75715e"&gt;// 出错退出&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; &lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Setsid fail&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;run in grandchild process&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($pid &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Couldn’t create child process.&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//在子进程中处理&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;run in child process.&amp;#34;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//posix_kill(posix_getpid(), SIGUSR1);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通常还会把子进程的pid收集以来，以便监控、回收，如&lt;a class="link" href="http://www.workerman.net/" target="_blank" rel="noopener"&#10; &gt;workerman&lt;/a&gt;。二次创建子进程通常应用在PHP多进程，守护进程上，比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;defined&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;DEAMON_LOCK_FILE&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;DEAMON_LOCK_FILE&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;run/deamon.pid&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($_SERVER[&lt;span style="color:#e6db74"&gt;&amp;#39;argc&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; $_SERVER[&lt;span style="color:#e6db74"&gt;&amp;#39;argv&amp;#39;&lt;/span&gt;][&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;kill&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$fh &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;realpath&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DEAMON_LOCK_FILE&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fread&lt;/span&gt;($fh, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $pid )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;posix_kill&lt;/span&gt;($pid, &lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $DEAMON_LOCK_HANDLER;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;daemonize&lt;/span&gt;($signalHandler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $DEAMON_LOCK_HANDLER;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( &lt;span style="color:#f92672"&gt;!&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deamon_file_lock&lt;/span&gt;() ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Deamon is already running...&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;umask&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $pid &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Can&amp;#39;t fork&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $pid ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$sid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;posix_setsid&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $sid &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Can&amp;#39;t set session leader&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;deamon_bind_signals&lt;/span&gt;($signalHandler);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $pid &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; $pid ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;ftruncate&lt;/span&gt;($DEAMON_LOCK_HANDLER, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;fwrite&lt;/span&gt;($DEAMON_LOCK_HANDLER, &lt;span style="color:#a6e22e"&gt;posix_getpid&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;chdir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;STDIN&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;STDOUT&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;STDERR&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deamon_bind_signals&lt;/span&gt;($signalHandler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$signalHandler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;$signalHandler &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;deamon_signal_handler&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; $signalHandler;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt;, $signalHandler);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGHUP&lt;/span&gt;, $signalHandler);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGUSR1&lt;/span&gt;, $signalHandler);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGINT&lt;/span&gt;, $signalHandler);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deamon_file_lock&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $DEAMON_LOCK_HANDLER;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$DEAMON_LOCK_HANDLER &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;realpath&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DEAMON_LOCK_FILE&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( &lt;span style="color:#f92672"&gt;!&lt;/span&gt; $DEAMON_LOCK_HANDLER ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Can&amp;#39;t open lock file&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;flock&lt;/span&gt;( $DEAMON_LOCK_HANDLER, &lt;span style="color:#a6e22e"&gt;LOCK_EX&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LOCK_NB&lt;/span&gt; ) ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deamon_signal_handler&lt;/span&gt;($signo) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt;( $signo ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGHUP&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGUSR1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sighandler&lt;/span&gt;($sig) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//do something&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( $sig &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGTERM&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $DEAMON_LOCK_HANDLER;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;( $DEAMON_LOCK_HANDLER );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;daemonize&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;sighandler&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;( &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_signal_dispatch&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// do something here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;( &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以通过ps -ef | grep php查看过程中的php进程产生情况，CentOS下安装PHP5.4的Posix扩展为：sudo yum instal php54w-process。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="http://php.net/manual/zh/function.pcntl-signal.php" target="_blank" rel="noopener"&#10; &gt;pcntl_signal&lt;/a&gt;可以注册信号处理函数，捕获信号后交给对应回调函数处理，实现信号通信，例如当某一子进程结束、中断或恢复执行时，内核会发送SIGCHLD信号予其父进程&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ticks&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGCHLD&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;signal_handler&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;signal_handler&lt;/span&gt;($signal) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt;($signal) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SIGCHLD&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;pcntl_waitpid&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, $status) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_wexitstatus&lt;/span&gt;($status);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Child &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$status&lt;/span&gt;&lt;span style="color:#e6db74"&gt; completed&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$pid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pcntl_fork&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$pid) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;print&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;In child &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$i&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;($i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// parent does processing here...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="http://php.net/manual/zh/function.pcntl-alarm.php" target="_blank" rel="noopener"&#10; &gt;pcntl_alarm&lt;/a&gt;创建一个计时器，在指定的秒数后向进程发送一个SIGALRM信号，结合pcntl_signal和pcntl_alarm可以做一个秒级的定时器（注意：pcntl_alarm是一次性消耗，需要再次设置）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;declare&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ticks&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;signal_handler&lt;/span&gt;($signal) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//do your work here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;print&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Caught SIGALRM&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;pcntl_alarm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pcntl_signal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SIGALRM&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;signal_handler&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pcntl_alarm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用PHP的进程控制便可以实现守护进程监控，如socke端口监听；多进程处理，如socke请求事件处理、任务并行、异步处理，提升PHP程序性能。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/intro.pcntl.php" target="_blank" rel="noopener"&#10; &gt;PHP 进程控制&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.hackingwithphp.com/16/1/3/getting-into-multiprocessing" target="_blank" rel="noopener"&#10; &gt;Getting into multiprocessing&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.hackingwithphp.com/16/1/2/timing-your-signals" target="_blank" rel="noopener"&#10; &gt;Timing your signals&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://systemsarchitect.net/php-deamon/" target="_blank" rel="noopener"&#10; &gt;PHP Deamon&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/lgg201/article/details/5996444" target="_blank" rel="noopener"&#10; &gt;PHP中利用pcntl进行多进程并发控制&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://netkiller.github.io/journal/php.daemon.html" target="_blank" rel="noopener"&#10; &gt;PHP高级编程之守护进程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://justwinit.cn/post/6457/" target="_blank" rel="noopener"&#10; &gt;PHP多进程编程一，PHP多进程编程二。&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.phppan.com/2013/02/php-ticks/" target="_blank" rel="noopener"&#10; &gt;PHP的ticks机制&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/yjf512/p/3288477.html" target="_blank" rel="noopener"&#10; &gt;PHP如何将进程作为守护进程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://andytson.com/blog/2010/05/daemonising-a-php-cli-script-on-a-posix-system/" target="_blank" rel="noopener"&#10; &gt;Daemonising a PHP cli script on a posix system&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://wiki.swoole.com/wiki/page/244.html" target="_blank" rel="noopener"&#10; &gt;异步毫秒定时器&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.hackingwithphp.com/4/21/0" target="_blank" rel="noopener"&#10; &gt;The declare() function and ticks&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://zh.wikipedia.org/wiki/%E5%AD%90%E8%BF%9B%E7%A8%8B" target="_blank" rel="noopener"&#10; &gt;子进程&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 扩展开发之C</title><link>https://courages.us/php-%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8Bc/</link><pubDate>Thu, 11 Jun 2015 23:06:33 +0800</pubDate><guid>https://courages.us/php-%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8Bc/</guid><description>&lt;p&gt;前面介绍了使用&lt;a class="link" href="https://courages.us/php-%e6%89%a9%e5%b1%95%e5%bc%80%e5%8f%91%e4%b9%8bzephir/" target="_blank" rel="noopener"&#10; &gt;Zephir来开发PHP扩展&lt;/a&gt;，将PHP代码转为扩展，以提升性能，保护代码。目前更多的扩展都是采用C/C++开发的，最近在项目开发中，需要在这些已有的PHP扩展上开发，也只能用C/C++来开发了。&lt;/p&gt;&#10;&lt;p&gt;首先去&lt;a class="link" href="http://www.php.net" target="_blank" rel="noopener"&#10; &gt;PHP官网&lt;/a&gt;下载对应版本的PHP源码，解压并进入对应的目录。&lt;br&gt;&#10;创建扩展courages：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 ext&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./ext_skel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./ext_skel --extname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;module &lt;span style="color:#f92672"&gt;[&lt;/span&gt;--proto&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;--stubs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;--xml&lt;span style="color:#f92672"&gt;[=&lt;/span&gt;file&lt;span style="color:#f92672"&gt;]]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;--skel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dir&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;--full-xml&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;--no-help&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --extname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;module module is the name of your extension&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --proto&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file file contains prototypes of functions to create&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --stubs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file generate only &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; stubs in file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --xml generate xml documentation to be added to phpdoc-cvs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --skel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dir path to the skeleton directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --full-xml generate xml documentation &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a self-contained extension&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;not yet implemented&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --no-help don&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;t try to be nice and create comments in the code&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; and helper functions to test &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; the module compiled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 ext&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ ./ext_skel --extname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;courages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating directory courages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Creating basic files: config.m4 config.w32 .svnignore courages.c php_courages.h CREDITS EXPERIMENTAL tests/001.phpt courages.php &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;To use your new extension, you will have to execute the following steps:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1. $ cd ..&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2. $ vi ext/courages/config.m4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3. $ ./buildconf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4. $ ./configure --&lt;span style="color:#f92672"&gt;[&lt;/span&gt;with|enable&lt;span style="color:#f92672"&gt;]&lt;/span&gt;-courages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5. $ make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6. $ ./sapi/cli/php -f ext/courages/courages.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7. $ vi ext/courages/courages.c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8. $ make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Repeat steps 3-6 &lt;span style="color:#66d9ef"&gt;until&lt;/span&gt; you are satisfied with ext/courages/config.m4 and&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;step &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; confirms that your module is compiled into PHP. Then, start writing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;code and repeat the last two steps as often as necessary.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的步骤说的很清楚，但这一次，步骤3被phpize代替了。&lt;/p&gt;&#10;&lt;p&gt;按部就班，编辑config.m4，PHP_ARG_WITH是采用动态库方式加载（PHP_ARG_ENABLE则是编译内核中，configure是–enable-extension使用），将&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dnl PHP_ARG_WITH(courages, whether to enable courages support,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dnl Make sure that the comment is aligned:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dnl [ --with-courages Include courages support])&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改为&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP_ARG_WITH(courages, for courages support,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ --with-courages Include courages support])&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后，在php_courages.h增加函数声明&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP_FUNCTION(confirm_courages_compiled);&#9;&lt;span style="color:#75715e"&gt;/* For testing, remove later. */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP_FUNCTION(courages_helloworld);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着，编辑courages.c，在function_entry中增加函数注册&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; zend_function_entry courages_functions[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;PHP_FE(confirm_courages_compiled,&#9;NULL)&#9;&#9;&lt;span style="color:#75715e"&gt;/* For testing, remove later. */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;PHP_FE(courages_helloworld, NULL)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;PHP_FE_END&#9;&lt;span style="color:#75715e"&gt;/* Must be the last line in courages_functions[] */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是courages_helloworld函数实现&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PHP_FUNCTION(courages_helloworld)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;arg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; arg_len, len;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;strg;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, &lt;span style="color:#e6db74"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;arg, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;arg_len) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; FAILURE) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;len &lt;span style="color:#f92672"&gt;=&lt;/span&gt; spprintf(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;strg, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Your input string: %s/n&amp;#34;&lt;/span&gt;, arg);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;php_printf(strg);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; SUCCESS;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后就是编译&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在php.ini中增加扩展courages.so&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[courages]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension = courages.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 courages&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ php -m | grep &lt;span style="color:#e6db74"&gt;&amp;#39;courages&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;courages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;vagrant@vagrant-centos64 courages&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ php courages.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Functions available in the test extension:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;confirm_courages_compiled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;courages_helloworld&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Your input string: hellow world&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Congratulations! You have successfully modified ext/courages/config.m4. Module courages is now compiled into PHP.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;到这里一个扩展的开发流程就结束了。&lt;/p&gt;&#10;&lt;p&gt;这里分享一些小技巧。&lt;br&gt;&#10;首先是如何在PHP扩展中获取PHP全局数组$_SERVER($_POST/GET)变量中的值：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get_server_var_by_name&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;str){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// This code makes sure $_SERVER has been initialized&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;zend_hash_exists(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;EG(symbol_table), &lt;span style="color:#e6db74"&gt;&amp;#34;_SERVER&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;zend_auto_global&lt;span style="color:#f92672"&gt;*&lt;/span&gt; auto_global;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (zend_hash_find(CG(auto_globals), &lt;span style="color:#e6db74"&gt;&amp;#34;_SERVER&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;auto_global) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; FAILURE) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;auto_global&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;armed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; auto_global&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;auto_global_callback(auto_global&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;name, auto_global&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;name_len TSRMLS_CC);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;// This fetches $_SERVER[&amp;#39;PHP_SELF&amp;#39;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;zval&lt;span style="color:#f92672"&gt;**&lt;/span&gt; arr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (zend_hash_find(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;EG(symbol_table), &lt;span style="color:#e6db74"&gt;&amp;#34;_SERVER&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;arr) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; FAILURE) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;HashTable&lt;span style="color:#f92672"&gt;*&lt;/span&gt; ht &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Z_ARRVAL_P(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;arr);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;zval&lt;span style="color:#f92672"&gt;**&lt;/span&gt; val;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (zend_hash_find(ht, str, strlen(str)&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&lt;span style="color:#f92672"&gt;**&lt;/span&gt;)&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;val) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; FAILURE) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;script_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Z_STRVAL_PP(val);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是如何在PHP扩展调用PHP函数:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*调用无参数函数*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get_sapi_name&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zval &lt;span style="color:#f92672"&gt;*&lt;/span&gt;function_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zval &lt;span style="color:#f92672"&gt;*&lt;/span&gt;retval;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;sapi_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MAKE_STD_ZVAL(function_name);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ZVAL_STRING(function_name , &lt;span style="color:#e6db74"&gt;&amp;#34;php_sapi_name&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (call_user_function_ex(EG(function_table), NULL, function_name, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;retval, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, NULL, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, EG(active_symbol_table) TSRMLS_CC) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; SUCCESS)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zend_error(E_ERROR, &lt;span style="color:#e6db74"&gt;&amp;#34;Function call failed&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (retval &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; Z_TYPE_P(retval) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; IS_STRING) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; convert_to_string(retval);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sapi_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Z_STRVAL_P(retval);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;sapi_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cli&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; sapi_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*调用有参数函数*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_ck_dir&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;dir TSRMLS_DC)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zval &lt;span style="color:#f92672"&gt;*&lt;/span&gt;function_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zval &lt;span style="color:#f92672"&gt;*&lt;/span&gt;retval;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zval &lt;span style="color:#f92672"&gt;*&lt;/span&gt;str;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zval &lt;span style="color:#f92672"&gt;**&lt;/span&gt;param[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MAKE_STD_ZVAL(function_name);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ZVAL_STRING(function_name , &lt;span style="color:#e6db74"&gt;&amp;#34;is_dir&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MAKE_STD_ZVAL(str);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ZVAL_STRING(str, dir, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; param[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;str;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (call_user_function_ex(EG(function_table), NULL, function_name, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;retval, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, param, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, EG(active_symbol_table) TSRMLS_CC) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; SUCCESS)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zend_error(E_ERROR, &lt;span style="color:#e6db74"&gt;&amp;#34;Function call failed&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (retval &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; NULL &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; zval_is_true(retval)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; SUCCESS;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; FAILURE;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更高级的一些技巧可以参考&lt;a class="link" href="https://github.com/walu/phpbook" target="_blank" rel="noopener"&#10; &gt;《PHP扩展开发及内核应用》&lt;/a&gt;和阅读别人的扩展开发代码。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://my.huhoo.net/archives/2008/02/php_ip.html" target="_blank" rel="noopener"&#10; &gt;php扩展实战 —— 获得ip的来源地址&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://rango.swoole.com/archives/152" target="_blank" rel="noopener"&#10; &gt;如何编写一个PHP的C扩展&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/heiyeshuwu/article/details/3453854" target="_blank" rel="noopener"&#10; &gt;[原创]快速开发一个PHP扩展&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2009/04/28/719.html" target="_blank" rel="noopener"&#10; &gt;用C/C++扩展你的PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/12007841/get-the-name-of-running-script-from-a-php-extension" target="_blank" rel="noopener"&#10; &gt;Get the name of running script from a PHP extension&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/13660407/build-php-extension-and-use-call-user-function" target="_blank" rel="noopener"&#10; &gt;Build PHP extension and use call_user_function&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://docstore.mik.ua/orelly/webprog/php/ch14_10.htm" target="_blank" rel="noopener"&#10; &gt;Programming PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/internals2.buildsys.configunix.php" target="_blank" rel="noopener"&#10; &gt;与 UNIX 构建系统交互: config.m4&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://forums.phpfreaks.com/topic/1303-call-user-function-ex-documentation/" target="_blank" rel="noopener"&#10; &gt;call_user_function_ex() documentation&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.kchodorow.com/blog/2011/08/11/php-extensions-made-eldrich-php-variables/" target="_blank" rel="noopener"&#10; &gt;PHP Extensions Made Eldrich: PHP Variables&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/3606125/convert-zval-to-char" target="_blank" rel="noopener"&#10; &gt;Convert Zval to char*&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://weizhifeng.net/write-php-extension-part1.html" target="_blank" rel="noopener"&#10; &gt;PHP扩展编写第一步：PHP和Zend介绍&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.phppan.com/2010/11/php-extension-1-simple-class/" target="_blank" rel="noopener"&#10; &gt;PHP扩展开发：简单类实现&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.imsiren.com/archives/572" target="_blank" rel="noopener"&#10; &gt;自己写PHP扩展之创建一个类[原创]&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.imsiren.com/archives/606" target="_blank" rel="noopener"&#10; &gt;如何在扩展里调用PHP函数呢?&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP队列开发之Beanstalk</title><link>https://courages.us/php%E9%98%9F%E5%88%97%E5%BC%80%E5%8F%91%E4%B9%8Bbeanstalk/</link><pubDate>Mon, 08 Jun 2015 17:02:01 +0800</pubDate><guid>https://courages.us/php%E9%98%9F%E5%88%97%E5%BC%80%E5%8F%91%E4%B9%8Bbeanstalk/</guid><description>&lt;p&gt;&lt;a class="link" href="http://kr.github.io/beanstalkd/" target="_blank" rel="noopener"&#10; &gt;Beanstalk&lt;/a&gt;是一个基于内存的（binlog持久化到硬盘），事件驱动（libevent），简单、快速的任务队列，支持大部分&lt;a class="link" href="https://github.com/kr/beanstalkd/wiki/client-libraries" target="_blank" rel="noopener"&#10; &gt;编程语言&lt;/a&gt;，将前台的任务转为后台异步处理，为web开发提供更高弹性。它可以支持多个server（客户端支持），一个任务只会被投递到一台server，一个任务只会被一个消费者获取（Reverse）。&lt;/p&gt;&#10;&lt;p&gt;相比&lt;a class="link" href="https://www.rabbitmq.com/" target="_blank" rel="noopener"&#10; &gt;RabbitMQ&lt;/a&gt;，Beanstalk作为一个任务队列，设计比较简单，支持以下特性：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;优先级（priority），可以对任务进行优先处理（或降级），越小的值优先级越高（0～4,294,967,295），默认按先进先出（FIFO）&lt;/li&gt;&#10;&lt;li&gt;延迟执行（delay），一个任务创建完成并稍后再执行（比如等待主从同步）&lt;/li&gt;&#10;&lt;li&gt;超时重试（TTR），一个任务没有在指定时间内完成，将会被重新投递，由其他客户端处理。客户端也可以主动进行延时（touch)或重新入队（release）&lt;/li&gt;&#10;&lt;li&gt;隐藏（bury），一个任务执行失败了，可以先隐藏，隐藏的任务可以被重新激活（kick）；&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;一个任务如果没有被删除，那么它就可以被重新获取。下面是大多数任务的生命周期:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; put with delay release with delay&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ----------------&amp;gt; [DELAYED] &amp;lt;------------.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | (time passes) |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; put v reserve | delete&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -----------------&amp;gt; [READY] ---------&amp;gt; [RESERVED] --------&amp;gt; *poof*&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ^ ^ | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | \ release | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | `-------------&amp;#39; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | kick |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | bury |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [BURIED] &amp;lt;---------------&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | delete&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; `--------&amp;gt; *poof*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CentOS下安装Beanstalkd&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install beanstalkd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#启动beanstalk&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service beanstalkd start&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#beanstalkd -l 192.168.33.14 -p 11300&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP下面有个C扩展&lt;a class="link" href="https://github.com/nil-zhang/php-beanstalk" target="_blank" rel="noopener"&#10; &gt;beanstalk库&lt;/a&gt;可以使用，基于libbeanstalkclient&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/bergundy/libbeanstalkclient.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd libbeanstalkclient&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir m4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#开始编译&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ./autogen.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#创建libbeanstalkclient.conf，内容为/usr/lib&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/ld.so.conf.d/libbeanstalkclient.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#使配置生效&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo ldconfig&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/nil-zhang/php-beanstalk.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd php-beanstalk&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑php.ini增加以下内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[beanstalk]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension = &amp;#34;beanstalk.so&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看是否加载成功&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php -m&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#加载成功则重启php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service php-fpm restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PHP测试代码&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Beanstalk&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addserver&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.14&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11300&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addserver&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.12&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11300&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $tubes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;list_tubes&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;print_r&lt;/span&gt;($tubes);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;; $i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;use&lt;/span&gt;($key);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;put&lt;/span&gt;($key, $value);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$key&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\t&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$value&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;watch&lt;/span&gt;($key);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $job &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;reserve&lt;/span&gt;($key);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;print_r&lt;/span&gt;($job);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bury&lt;/span&gt;($job[&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;], $key))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bury ok&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bury failed&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;kick&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, $key);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;delete&lt;/span&gt;($job[&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;], $key))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;delete ok&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;delete failed &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bsc&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ignore&lt;/span&gt;($key);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;done&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意由于Beanstalk服务端实现的比较简单，协议特性需要客户端支持，不同的实现可能效果不一样，这个客户端并没有实现延时发送（delay），超时重试（TTR）。需要这些特性建议使用这个库：&lt;a class="link" href="http://php-beanstalk.readthedocs.org/en/latest/" target="_blank" rel="noopener"&#10; &gt;PHP Beanstalkd&lt;/a&gt;。前台生产者创建任务：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;lib/Beanstalk.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Beanstalk&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;init&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addServer&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;192.168.33.14&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11300&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addServer&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;192.168.33.12&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11300&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;useTube&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;my-tube&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;put&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Hello World!&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;put&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Hello World!2&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1023&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;put&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;json_encode&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;what&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;how&amp;#39;&lt;/span&gt;)), &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后台消费者处理任务&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;lib/Beanstalk.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Beanstalk&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;init&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addServer&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;192.168.33.12&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11300&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addServer&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;192.168.33.14&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;11300&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;watchTube&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;my-tube&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$job &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $bean&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;reserve&lt;/span&gt;($timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;/* process job ... */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($job);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//var_dump($job-&amp;gt;getMessage());&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$job&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;delete&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;BeanstalkException&lt;/span&gt; $e)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; ($e&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getCode&lt;/span&gt;())&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BeanstalkException&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;TIMED_OUT&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Timed out waiting for a job. Retrying in 1 second.&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; $e;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：客户端获取任务（reverse）是阻塞的（blocking），直到超时；同一个队列（tube）的任务按FIFO进行处理（除非指定优先级）；任务内容长度不能超过65536；作为内存队列需要注意是否会内存超出，可以快速处理到Mysql。&lt;/p&gt;&#10;&lt;p&gt;使用Beanstalk任务队列提升PHP异步处理能力，降低程序耦合度，使前台更专注，后台处理耗时、扩展性任务（也可以使用其他语言开发），使得web架构更具扩展性。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://www.igvita.com/2010/05/20/scalable-work-queues-with-beanstalk/" target="_blank" rel="noopener"&#10; &gt;Scalable Work Queues with Beanstalk&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://raw.githubusercontent.com/kr/beanstalkd/master/doc/protocol.txt" target="_blank" rel="noopener"&#10; &gt;Beanstalk Protocol&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/kr/beanstalkd/wiki/faq" target="_blank" rel="noopener"&#10; &gt;Frequently Asked Questions for beanstalkd&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.lornajane.net/posts/2014/getting-started-with-beanstalkd" target="_blank" rel="noopener"&#10; &gt;Getting Started with Beanstalkd&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/JurianSluiman/queue-your-work" target="_blank" rel="noopener"&#10; &gt;Queue your work&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.codepath.com/2013/01/06/asynchronous-processing-in-web-applications-part-2-developers-need-to-understand-message-queues/" target="_blank" rel="noopener"&#10; &gt;Asynchronous Processing in Web Applications, Part 2: Developers Need to Understand Message Queues&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>&lt;img src="http://courages.us/wp-content/uploads/2015/05/logo.gif" alt="PHP" width="40" height="20"&gt;PHP 7</title><link>https://courages.us/php-7/</link><pubDate>Sat, 30 May 2015 18:18:49 +0800</pubDate><guid>https://courages.us/php-7/</guid><description>&lt;p&gt;最近学习了&lt;a class="link" href="http://www.infoq.com/cn/presentations/php7-new-engine-for-good-old-train" target="_blank" rel="noopener"&#10; &gt;PHP 7介绍的视频&lt;/a&gt;，看到了PHP每一天都在变好。PHP 将会带来许多新的特性：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;抽象语法树，在编译opcode时能够做更多的优化&lt;/li&gt;&#10;&lt;li&gt;INT64提升，支持大于2GB的字符串/文件上传&lt;/li&gt;&#10;&lt;li&gt;标量类型声明，可以声明参数类型&lt;/li&gt;&#10;&lt;li&gt;返回值声明，可以声明返回值类型&lt;/li&gt;&#10;&lt;li&gt;新操作符，&amp;lt;=&amp;gt;操作符，大于返回1，等于返回0，小于返回-1&lt;/li&gt;&#10;&lt;li&gt;统一变量语法；&lt;/li&gt;&#10;&lt;li&gt;引擎异常改进，函数不存在的fata error转为异常可以捕获处理&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;等等。&lt;br&gt;&#10;除了新特性外，PHP 7使用了新引擎&lt;a class="link" href="https://wiki.php.net/phpng" target="_blank" rel="noopener"&#10; &gt;PHP NG&lt;/a&gt;，性能得到了巨大的提升（&lt;a class="link" href="http://www.laruence.com/2014/12/18/2976.html" target="_blank" rel="noopener"&#10; &gt;与HHVM对比&lt;/a&gt;）。&lt;br&gt;&#10;这里的性能优化比较有意思， 非常值得借鉴学习。为什么要进行重构：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;PHP 5.4之后php引擎的性能提升已经不大，Zend VM已经高度优化&lt;/li&gt;&#10;&lt;li&gt;PHP JIT(Just In Time Compiler)项目在benchmakr上性能提升巨大（8倍），但是在实际业务提升不大（离开实际业务谈benchmark都是耍流氓）&lt;/li&gt;&#10;&lt;li&gt;分析wordpress项目发现瓶颈并不在Zend VM上面，21% CPU时间花在了内存管理，12%时间花在了hashTable操作，30% CPU时间花在了内部调用，25% CUP时间花在了VM&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;首先应当分析实际业务的性能消耗占比，确定需要优化的地方。JIT仅仅优化了Zend VM，提升是有限的，需要对其他地方（内存操作，HashTable，函数调用）也进行优化，所以才进行的重构。&lt;/p&gt;&#10;&lt;p&gt;PHP NG在很多方面做了优化：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;标量类型不做引用计数，zval分配在堆上，增加Referance类型&lt;/li&gt;&#10;&lt;li&gt;增加类型zend string，将字符串与值连续分配，避免CPU cache miss，避免二次读内存&lt;/li&gt;&#10;&lt;li&gt;原本的HashTable变为zend array，数组值为zval，内存一次分配，提升data locality，避免CPU cache miss&lt;/li&gt;&#10;&lt;li&gt;函数调用优化，减少重复入栈&lt;/li&gt;&#10;&lt;li&gt;参数解析优化，将不确定转化为确定&lt;/li&gt;&#10;&lt;li&gt;zend_qsort排序优化&lt;/li&gt;&#10;&lt;li&gt;内存管理优化，减少CPU cache miss&lt;/li&gt;&#10;&lt;li&gt;常用函数优化&lt;/li&gt;&#10;&lt;li&gt;字符串拼接优化，减少内存访问次数&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;通过这一系列的优化，改进了PHP的内存操作，改进了HashTable操作，改进了内部函数调用，降低了CPU 时间消耗，这时候再来做PHP JIT优化就有意义。PHP 7接下来仍然会继续优化，迁移常用扩展。&lt;br&gt;&#10;许多优化都是微小的，但是积累起来后却是巨大，特别是对于微博这样的网站，1%的性能提升都意义非凡。&lt;br&gt;&#10;优化是具有专向性的，对A场景的优化可能并不适合B场景，所以需要分析实际的业务中的瓶颈和调用频次，权衡优化的方向。&lt;br&gt;&#10;现在距离10月份发布已经不远了，大家也可以检查自己项目是否兼容PHP 7，性能提升多少。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/presentations/php7-new-engine-for-good-old-train" target="_blank" rel="noopener"&#10; &gt;PHP7 – New engine for good old train&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2014/12/18/2976.html" target="_blank" rel="noopener"&#10; &gt;PHP7 VS HHVM (WordPress)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://wiki.php.net/phpng" target="_blank" rel="noopener"&#10; &gt;PHPNG (next generation)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.sitepoint.com/php-fights-hhvm-zephir-phpng/" target="_blank" rel="noopener"&#10; &gt;What to Expect When You’re Expecting: PHP 7, Part 1&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://philsturgeon.uk/php/2015/03/15/php-7-feature-freeze/" target="_blank" rel="noopener"&#10; &gt;PHP 7 Feature Freeze&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://hhvm.com/" target="_blank" rel="noopener"&#10; &gt;HHVM&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://wuduoyi.com/note/hhvm/" target="_blank" rel="noopener"&#10; &gt;HHVM 是如何提升 PHP 性能的？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.sitepoint.com/php-fights-hhvm-zephir-phpng/" target="_blank" rel="noopener"&#10; &gt;PHP Fights HHVM and Zephir with PHPNG&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/rlerdorf/php7dev" target="_blank" rel="noopener"&#10; &gt;rlerdorf/php7dev&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://akrabat.com/building-and-testing-php7/" target="_blank" rel="noopener"&#10; &gt;Building and testing the upcoming PHP7&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.zimuel.it/install-php-7/" target="_blank" rel="noopener"&#10; &gt;Install PHP 7 on Ubuntu 14.04&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP yield应用</title><link>https://courages.us/php-yield%E5%BA%94%E7%94%A8/</link><pubDate>Mon, 25 May 2015 18:48:33 +0800</pubDate><guid>https://courages.us/php-yield%E5%BA%94%E7%94%A8/</guid><description>&lt;p&gt;PHP 5.5开始新增了神奇的关键字yield，能够从生成器（generators）中返回数据。yield有点像普通函数中的关键字return，但是不会彻底停止函数的执行（普通函数一旦return便不执行了），可以暂停循环并返回值，每一次调用便从中断处继续迭代。生成器可以用于替代循环迭代，每一次调用返回一个&lt;a class="link" href="http://php.net/manual/en/class.generator.php" target="_blank" rel="noopener"&#10; &gt;生成器对象（generator）&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;yield能够延迟执行，可以用于对大量数据进行迭代而不用预先在内存中生成数组。例如动态生成一个大数组：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;xrange&lt;/span&gt;($start, $end, $step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $start; $i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; $end; $i &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; $step) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; $i;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;xrange&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $num) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $num, &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$range &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;xrange&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1000000&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($range); &lt;span style="color:#75715e"&gt;// object(Generator)#1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;var_dump&lt;/span&gt;($range &lt;span style="color:#a6e22e"&gt;instanceof&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Iterator&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// bool(true)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用yield简便、高效的生成fibonacci数列而不是循环或递归&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fibonacci&lt;/span&gt;($count) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $prev &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; $count; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; $prev;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $next &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $prev &lt;span style="color:#f92672"&gt;+&lt;/span&gt; $current;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $prev &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $current;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $current &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $next;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;fibonacci&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $i &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $value) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $i , &lt;span style="color:#e6db74"&gt;&amp;#39; -&amp;gt; &amp;#39;&lt;/span&gt; , $value, &lt;span style="color:#a6e22e"&gt;PHP_EOL&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用yield来循环读取文件，而不需要像file函数那样一次性加载进来，节省内存&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file_lines&lt;/span&gt;($filename) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;($filename, &lt;span style="color:#e6db74"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (($line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fgets&lt;/span&gt;($file)) &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; $line; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($file); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;file_lines&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;somefile&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $line) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// do some work here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;yield除了能够返回值，用作变量时还可以接收值。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;($fileName) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $fileHandle &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;($fileName, &lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fwrite&lt;/span&gt;($fileHandle, &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$logger &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__DIR__&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/log&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$logger&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Foo&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$logger&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Bar&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于yield具有中断执行后再次调用又可以从中断处执行，外界又可以通过&lt;a class="link" href="http://php.net/manual/en/generator.send.php" target="_blank" rel="noopener"&#10; &gt;生成器对象（generator）的send方法&lt;/a&gt;进行交互，可以用于协程（coroutine），作多任务协作的流程控制。这里有个&lt;a class="link" href="https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html" target="_blank" rel="noopener"&#10; &gt;例子&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Task&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $taskId;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $coroutine;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $sendValue &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $beforeFirstYield &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($taskId, &lt;span style="color:#a6e22e"&gt;Generator&lt;/span&gt; $coroutine) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskId&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $taskId;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;coroutine&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $coroutine;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getTaskId&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskId&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setSendValue&lt;/span&gt;($sendValue) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sendValue&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $sendValue;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;beforeFirstYield&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;beforeFirstYield&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;coroutine&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;current&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $retval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;coroutine&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sendValue&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sendValue&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $retval;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;isFinished&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;coroutine&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;valid&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Scheduler&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $maxTaskId &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $taskMap &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []; &lt;span style="color:#75715e"&gt;// taskId =&amp;gt; task&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $taskQueue;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskQueue&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SplQueue&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newTask&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Generator&lt;/span&gt; $coroutine) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $tid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;maxTaskId&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $task &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Task&lt;/span&gt;($tid, $coroutine);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskMap&lt;/span&gt;[$tid] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $task;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;schedule&lt;/span&gt;($task);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $tid;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;schedule&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Task&lt;/span&gt; $task) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskQueue&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;enqueue&lt;/span&gt;($task);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskQueue&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isEmpty&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $task &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskQueue&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dequeue&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $task&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($task&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;isFinished&lt;/span&gt;()) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;taskMap&lt;/span&gt;[$task&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getTaskId&lt;/span&gt;()]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;schedule&lt;/span&gt;($task);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task1&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;This is task 1 iteration &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$i&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;task2&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ($i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; $i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;$i) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;This is task 2 iteration &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$i&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;yield&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$scheduler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Scheduler&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$scheduler&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;newTask&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;task1&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$scheduler&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;newTask&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;task2&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$scheduler&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有些任务是需要交互进行的，如socket的监听和回复；有些任务异步执行又需要回调，如A执行不阻塞程序，但B执行又取决于A是否执行完毕。这些都可以使用yield来进行封装，达到流程控制的目的。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/en/language.generators.overview.php" target="_blank" rel="noopener"&#10; &gt;Generators overview&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/17483806/what-does-yield-mean-in-php" target="_blank" rel="noopener"&#10; &gt;What does yield mean in PHP?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/17223802/what-is-the-difference-between-a-generator-and-an-array" target="_blank" rel="noopener"&#10; &gt;What is the difference between a generator and an array?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html" target="_blank" rel="noopener"&#10; &gt;Cooperative multitasking using coroutines (in PHP!)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.ircmaxell.com/2012/07/what-generators-can-do-for-you.html" target="_blank" rel="noopener"&#10; &gt;What Generators Can Do For You&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.masnun.com/2013/12/27/generators-and-coroutines-in-php.html" target="_blank" rel="noopener"&#10; &gt;Generators and Coroutines in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://Generators%20in%20PHP" target="_blank" rel="noopener"&#10; &gt;Generators in PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.hitoy.org/coroutine-and-yield.html" target="_blank" rel="noopener"&#10; &gt;协程与yield&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/recoilphp/recoil" target="_blank" rel="noopener"&#10; &gt;http://www.hitoy.org/coroutine-and-yield.html&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://medium.com/@assertchris/co-operative-php-multitasking-ce4ef52858a0" target="_blank" rel="noopener"&#10; &gt;Co-operative PHP Multitasking&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://en.wikipedia.org/wiki/Generator_%28computer_programming%29" target="_blank" rel="noopener"&#10; &gt;Generator (computer programming)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/presentations/optimization-of-asynchronous-processing-in-distributed-systems" target="_blank" rel="noopener"&#10; &gt;异步处理在分布式系统中的优化作用&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP异步IO</title><link>https://courages.us/php%E5%BC%82%E6%AD%A5io/</link><pubDate>Sat, 16 May 2015 12:08:24 +0800</pubDate><guid>https://courages.us/php%E5%BC%82%E6%AD%A5io/</guid><description>&lt;p&gt;为了能更快的响应请求，耗时任务的执行不能阻塞当前脚本执行，而是放在最后执行，比如&lt;a class="link" href="http://www.laruence.com/2011/04/13/1991.html" target="_blank" rel="noopener"&#10; &gt;fastcgi_finsh_request&lt;/a&gt;。现在又多了一个方法，PHP也可以进行异步IO处理了。&lt;/p&gt;&#10;&lt;p&gt;PHP扩展eio是基于C语言的&lt;a class="link" href="http://software.schmorp.de/pkg/libeio.html" target="_blank" rel="noopener"&#10; &gt;libeio&lt;/a&gt;库中开发的异步IO处理，可用于异步文件读写，自定义异步任务执行。Nodejs使用的libuv库封装了libeio和&lt;a class="link" href="http://software.schmorp.de/pkg/libev.html" target="_blank" rel="noopener"&#10; &gt;libev&lt;/a&gt;（libev也有对应的PHP扩展：&lt;a class="link" href="http://php.net/manual/zh/book.ev.php" target="_blank" rel="noopener"&#10; &gt;ev&lt;/a&gt;），前者提供异步IO，后者提供高性能的事件驱动，进行高性能的请求的处理。另外，PHP异步多线程框架&lt;a class="link" href="http://www.swoole.com/" target="_blank" rel="noopener"&#10; &gt;Swoole&lt;/a&gt;也提供了异步IO处理的能力。&lt;/p&gt;&#10;&lt;p&gt;在CentOS下编译安装PHP eio扩展:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://pecl.php.net/get/eio-1.2.5.tgz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -zxvf eio-1.2.5.tzg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd eio-1.2.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改php.ini添加扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[eio]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=eio.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看是否安装成功&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/eio0.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="eio0" class="gallery-image" data-flex-basis="521px" data-flex-grow="217" height="138" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/eio0-300x138.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;注意：eio扩展必须在socket扩展之后加载，否则会提示’ undefined symbol: php_sockets_le_socket in Unknown on line 0’。&lt;/p&gt;&#10;&lt;p&gt;PHP eio支持libeio的所有操作，当调用eio_poll/eio_event_loop时，触发IO处理，处理完成进行回调；未主动调用eio_poll/eio_event_loop则不阻塞当前程序执行，等待脚本执行结束后在提交异步处理。使用&lt;a class="link" href="http://php.net/manual/zh/function.eio-custom.php" target="_blank" rel="noopener"&#10; &gt;eio_custom&lt;/a&gt;和&lt;a class="link" href="http://php.net/manual/zh/function.eio-nop.php" target="_blank" rel="noopener"&#10; &gt;eio_nop&lt;/a&gt;可以自定义异步任务调用。&lt;/p&gt;&#10;&lt;p&gt;以下以写文件进行比较，示例一是常规的文件写操作：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strBasePath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dirname&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strFileName &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $strBasePath&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/file.log&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strContent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;something to log ...&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nStart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$rFile &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;($strFileName ,&lt;span style="color:#e6db74"&gt;&amp;#39;a+&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$nLength &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fwrite&lt;/span&gt;($rFile, $strContent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($rFile);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;done&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;register_shutdown_function&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $nStart;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nStart;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;示例二是PHP eio的异步写操作：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strBasePath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dirname&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strFileName &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $strBasePath&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/file.log&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strContent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;something to log ...&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nLenth &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($strContent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eioOpenCallBack&lt;/span&gt;($p_mxData ,$p_mxResult){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//echo &amp;#34;Open.\r\n&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($p_mxResult &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;eio_fstat&lt;/span&gt;($p_mxResult, &lt;span style="color:#a6e22e"&gt;EIO_PRI_DEFAULT&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;eioStatCallBack&amp;#34;&lt;/span&gt;, $p_mxResult);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eioStatCallBack&lt;/span&gt;($p_mxData ,$p_mxResult){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $strContent ,$nLenth;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//echo &amp;#34;Stat.\r\n&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($p_mxResult &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;eio_write&lt;/span&gt;($p_mxData, $strContent, $nLenth, $p_mxResult[&lt;span style="color:#e6db74"&gt;&amp;#39;size&amp;#39;&lt;/span&gt;], &lt;span style="color:#a6e22e"&gt;EIO_PRI_DEFAULT&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;eioWriteCallBack&amp;#34;&lt;/span&gt;, $p_mxData);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eioWriteCallBack&lt;/span&gt;($p_mxData ,$p_mxResult){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//echo &amp;#34;Write.\r\n&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($p_mxResult &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;eio_close&lt;/span&gt;($p_mxData, &lt;span style="color:#a6e22e"&gt;EIO_PRI_DEFAULT&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;eioCloseCallBack&amp;#34;&lt;/span&gt;, $p_mxData);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eioCloseCallBack&lt;/span&gt;($p_mxData ,$p_mxResult){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//echo &amp;#34;Close.\r\n&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($p_mxResult &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//echo &amp;#34;End\r\n&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nStart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;eio_open&lt;/span&gt;($strFileName, &lt;span style="color:#a6e22e"&gt;EIO_O_CREAT&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EIO_O_RDWR&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;EIO_S_IRUSR&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EIO_S_IWUSR&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;EIO_PRI_DEFAULT&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;eioOpenCallBack&amp;#34;&lt;/span&gt;, $strFileName);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//echo &amp;#34;Begin\r\n&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//eio_event_loop();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;done&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;register_shutdown_function&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $nStart;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nStart;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;示例三是swoole扩展的&lt;a class="link" href="http://wiki.swoole.com/wiki/page/189.html" target="_blank" rel="noopener"&#10; &gt;异步写操作&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strBasePath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dirname&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strFileName &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $strBasePath&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/file.log&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$strContent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;something to log ...&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$nStart &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;swoole_async_write&lt;/span&gt;($strFileName ,$strContent);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;done&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;register_shutdown_function&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;global&lt;/span&gt; $nStart;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;microtime&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; $nStart;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对比情况&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/eio1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="eio1" class="gallery-image" data-flex-basis="750px" data-flex-grow="312" height="96" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/eio1-300x96.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;可以看出，eio和swoole提交异步IO处理后，处理非常快，并未阻塞当前进程运行；eio更像是只花了循环的时间。swoole只能运行于CLI模式，使用了Linux Native AIO，处理非常快，写法也比较简单。eio可以运行于CGI和CLI模式，提交异步处理后会创建至多4个线程（eio_nthreads）进行处理，处理完成后仍然会返回主线程，所以PHP脚本执行结束后，主线程仍然会在在那里等待。eio的异步处理通过回调进行保证，写法上更加复杂。这就需要对异步回调进行包装，提供类似同步的代码，参见&lt;a class="link" href="http://www.zhihu.com/question/20511233" target="_blank" rel="noopener"&#10; &gt;协程&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/php%e5%bc%82%e6%ad%a5%e6%89%a7%e8%a1%8c%e5%90%8e%e5%8f%b0%e4%bb%bb%e5%8a%a1/" target="_blank" rel="noopener"&#10; &gt;PHP异步执行长时间任务&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.walu.cc/phpbook/1.3.md" target="_blank" rel="noopener"&#10; &gt;PHP的生命周期&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://wanghuanming.com/2014/09/libeio%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A0/" target="_blank" rel="noopener"&#10; &gt;libeio源码学习&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://justwinit.cn/post/5735/" target="_blank" rel="noopener"&#10; &gt;PHP新增eio扩展，可以写类似node.js一样的异步IO了&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.infoq.com/cn/articles/nodejs-asynchronous-io" target="_blank" rel="noopener"&#10; &gt;深入浅出Node.js（五）：初探Node.js的异步I/O实现&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://rango.swoole.com/archives/282" target="_blank" rel="noopener"&#10; &gt;异步AIO的研究&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://rango.swoole.com/archives/381" target="_blank" rel="noopener"&#10; &gt;关于C10K、异步回调、协程、同步阻塞&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B" target="_blank" rel="noopener"&#10; &gt;协程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://cnodejs.org/topic/4f16442ccae1f4aa270010a7" target="_blank" rel="noopener"&#10; &gt;linux AIO （异步IO） 那点事儿&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.zhihu.com/question/19585576" target="_blank" rel="noopener"&#10; &gt;什么程序设计语言机制是处理异步 IO 最恰当的抽象？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://cnodejs.org/topic/4f16442ccae1f4aa2700113b" target="_blank" rel="noopener"&#10; &gt;nodejs异步IO的实现&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.bo56.com/%E9%80%9A%E8%BF%87%E5%8D%8F%E7%A8%8B%E5%AE%9E%E7%8E%B0mysql%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%BC%82%E6%AD%A5%E5%8C%96/" target="_blank" rel="noopener"&#10; &gt;向facebook学习，通过协程实现mysql查询的异步化&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://segmentfault.com/a/1190000001813992" target="_blank" rel="noopener"&#10; &gt;Python 中的进程、线程、协程、同步、异步、回调&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://coolshell.cn/articles/10975.html" target="_blank" rel="noopener"&#10; &gt;一个“蝇量级” C 语言协程库&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>CentOS上安装Nginx+PHP-FPM</title><link>https://courages.us/php%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8Bnginxphp-fpm/</link><pubDate>Sun, 10 May 2015 11:06:08 +0800</pubDate><guid>https://courages.us/php%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8Bnginxphp-fpm/</guid><description>&lt;p&gt;&lt;a class="link" href="http://nginx.org/en/" target="_blank" rel="noopener"&#10; &gt;Nginx&lt;/a&gt;是一个高性能、轻量级的HTTP服务器，占用内存少，稳定性高，也可做为&lt;a class="link" href="https://courages.us/nginx%e5%81%9a%e7%ae%80%e5%8d%95%e7%9a%84%e5%8f%8d%e5%90%91%e4%bb%a3%e7%90%86/" target="_blank" rel="noopener"&#10; &gt;反向代理服务器&lt;/a&gt;。Nginx采用事件驱动，在Linux操作系统下，Nginx使用epoll事件模型，充分使用异步逻辑，削减了上下文调度开销，并发服务能力更强。&lt;/p&gt;&#10;&lt;p&gt;PHP-FPM是PHP的FastCGI 进程管理器，具有一些高级特性，将PHP进程管理与Web服务器分开，可以分开部署在不同机器上，监听不同的端口和使用不同的 php.ini 配置文件。&lt;/p&gt;&#10;&lt;p&gt;PHP-FPM特性之一：&lt;a class="link" href="http://php.net/manual/zh/function.fastcgi-finish-request.php" target="_blank" rel="noopener"&#10; &gt;fastcgi_finish_request&lt;/a&gt;能够在请求完成和刷新数据后，继续在后台执行耗时的工作（录入视频转换、统计处理等），达到分离执行后台任务而又不阻塞PHP快速响应，可作为PHP性能优化点。&lt;/p&gt;&#10;&lt;p&gt;PHP-FPM另一特性：可以记录请求当中慢响应的日志，类似Mysql满日志，包括文件名，函数名，行号等，可用于分析PHP的性能问题。&lt;/p&gt;&#10;&lt;p&gt;在Apache + mod_php下，每一个请求，Apache便会启动一个进程并加载php解释器来处理。在Nginx + PHP-FPM下，Nginx将PHP请求和环境变量通过socket传递给FastCGI进程；将静态资源请求则缓存到本地并返回。FastCGI 进程管理器采用固定静态（或动态）的子进程来处理请求，占用内存少，具有更好的扩展能力。&lt;/p&gt;&#10;&lt;p&gt;在CentOs 6.4上安装Nginx和PHP-FPM：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum search nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo chkconfig --levels &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; nginx on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service nginx start&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum search fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install php54-fpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑php.ini&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP&amp;#39;s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; of zero causes PHP to behave as before. Default is 1. You should fix your scripts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; http://www.php.net/manual/en/ini.core.php#ini.cgi.fix-pathinfo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cgi.fix_pathinfo=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动PHP-FPM&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chkconfig --levels &lt;span style="color:#ae81ff"&gt;235&lt;/span&gt; php-fpm on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service php-fpm start&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改Nginx worker_processes配置&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/nginx/nginx.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;worker_processes 4;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更改Nginx 配置以便处理php请求&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/nginx/conf.d/default.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80 default_server;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name _;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #charset koi8-r;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #access_log logs/host.access.log main;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # Load configuration files for the default server block.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /etc/nginx/default.d/*.conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index index.html index.htm;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page 404 /404.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location = /404.html {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # redirect server error pages to the static page /50x.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error_page 500 502 503 504 /50x.html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location = /50x.html {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # proxy the PHP scripts to Apache listening on 127.0.0.1:80&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #location ~ \.php$ {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # proxy_pass http://127.0.0.1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location ~ \.php$ {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /usr/share/nginx/html;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #fastcgi_pass 127.0.0.1:9000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_pass unix:/tmp/php5-fpm.sock;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_index index.php;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include fastcgi.conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # deny access to .htaccess files, if Apache&amp;#39;s document root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # concurs with nginx&amp;#39;s one&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #location ~ /\.ht {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # deny all;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; #}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑PHP-FPM&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php-fpm.d/www.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; List of ipv4 addresses of FastCGI clients which are allowed to connect.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; must be separated by a comma. If this value is left blank, connections will be&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; accepted from any ip address.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Default Value: any&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;listen.allowed_clients = 127.0.0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen = /tmp/php5-fpm.sock&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Set permissions for unix socket, if one is used. In Linux, read/write&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; permissions must be set in order to allow connections from a web server. Many&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; BSD-derived systems allow connections regardless of permissions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Default Values: user and group are set as the running user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; mode is set to 0660&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen.owner = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen.group = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;listen.mode = 0660&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Unix user/group of processes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Note: The user is mandatory. If the group is not set, the default user&amp;#39;s group&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;&#9;will be used.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; RPM: apache Choosed to be able to access some dir as httpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; RPM: Keep a group allowed to write in log dir.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;group = nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启PHP-FPM&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service php-fpm restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建PHP页面&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /usr/share/nginx/html/info.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;phpinfo&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启Nginx&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo service nginx restart&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试PHP是否正确处理。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/php-fpm.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="php-fpm" class="gallery-image" data-flex-basis="237px" data-flex-grow="99" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/php-fpm-297x300.png" width="297"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.if-not-true-then-false.com/2011/nginx-and-php-fpm-configuration-and-optimizing-tips-and-tricks/" target="_blank" rel="noopener"&#10; &gt;Nginx and PHP-FPM Configuration and Optimizing Tips and Tricks&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zh.wikipedia.org/wiki/Nginx" target="_blank" rel="noopener"&#10; &gt;nginx&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/install.fpm.php" target="_blank" rel="noopener"&#10; &gt;FastCGI 进程管理器（FPM）&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.a2o.si/2009/06/24/apache-mod_php-compared-to-nginx-php-fpm/" target="_blank" rel="noopener"&#10; &gt;Apache + mod_php compared to Nginx + php-fpm&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.layershift.com/which-php-mode-apache-vs-cgi-vs-fastcgi/" target="_blank" rel="noopener"&#10; &gt;Which PHP mode? Apache vs CGI vs FastCGI&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://serverfault.com/questions/6733/php-what-are-the-advantages-of-fastcgi-over-mod-php" target="_blank" rel="noopener"&#10; &gt;PHP: What are the advantages of FastCGI over mod_php?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.quora.com/What-are-the-advantages-of-using-PHP-FPM-&amp;#43;-Nginx-over-Apache-and-mod_php" target="_blank" rel="noopener"&#10; &gt;What are the advantages of using PHP-FPM + Nginx over Apache and mod_php?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.howtoforge.com/how-to-install-nginx-with-php5-and-php-fpm-and-mysql-on-centos-6.5-p2" target="_blank" rel="noopener"&#10; &gt;How To Install Nginx With PHP5 (And PHP-FPM) And MySQL Support On CentOS 6.5&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-centos-6" target="_blank" rel="noopener"&#10; &gt;How To Install Linux, nginx, MySQL, PHP (LEMP) stack on CentOS 6&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2009/07/28/1030.html" target="_blank" rel="noopener"&#10; &gt;Linux上配置Nginx+PHP5(FastCGI)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2011/04/13/1991.html" target="_blank" rel="noopener"&#10; &gt;使用fastcgi_finish_request提高页面响应速度&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.bo56.com/%E5%96%84%E7%94%A8php-fpm%E7%9A%84%E6%85%A2%E6%89%A7%E8%A1%8C%E6%97%A5%E5%BF%97slow-log%EF%BC%8C%E5%88%86%E6%9E%90php%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98/" target="_blank" rel="noopener"&#10; &gt;善用php-fpm的慢执行日志slow log，分析php性能问题&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.guangla.com/post/swoole-reload" target="_blank" rel="noopener"&#10; &gt;swoole之代码热更新实现&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 扩展开发之Zephir</title><link>https://courages.us/php-%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8Bzephir/</link><pubDate>Wed, 06 May 2015 21:26:24 +0800</pubDate><guid>https://courages.us/php-%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8Bzephir/</guid><description>&lt;p&gt;最近对代码进行性能分析后，发现两个耗时的地方：自动加载文件数太多；参数验证函数调用超过1000次。这也是许多php语言框架面临的问题，所以发展出来诸如&lt;a class="link" href="https://github.com/laruence/php-yaf" target="_blank" rel="noopener"&#10; &gt;Yaf&lt;/a&gt;，&lt;a class="link" href="http://www.swoole.com/" target="_blank" rel="noopener"&#10; &gt;Swoole&lt;/a&gt;，&lt;a class="link" href="http://phalconphp.com/en/" target="_blank" rel="noopener"&#10; &gt;Phalcon&lt;/a&gt;这些C语言扩展框架，或者类似&lt;a class="link" href="http://www.workerman.net/" target="_blank" rel="noopener"&#10; &gt;workerman&lt;/a&gt;，&lt;a class="link" href="http://reactphp.org/" target="_blank" rel="noopener"&#10; &gt;reactphp&lt;/a&gt;，&lt;a class="link" href="http://daemon.io/" target="_blank" rel="noopener"&#10; &gt;phpdaemon&lt;/a&gt;这些一次加载的框架。总之减少加载文件，使用内置函数，减少损耗，以提升性能。&lt;br&gt;&#10;相比之下，PHP扩展的框架性能还是要比PHP语言框架还要好不少。以往PHP扩展的开发方式就是&lt;a class="link" href="http://www.laruence.com/2009/04/28/719.html" target="_blank" rel="noopener"&#10; &gt;C/C++&lt;/a&gt;，&lt;a class="link" href="http://www.ibm.com/developerworks/cn/opensource/os-php-swig/?ca=drs-cn-0301" target="_blank" rel="noopener"&#10; &gt;SWIG&lt;/a&gt;，现在还多了一个选择：&lt;a class="link" href="https://github.com/FTDC/zephir" target="_blank" rel="noopener"&#10; &gt;zephir&lt;/a&gt;，从Phalcon发展出来的项目，采用类似PHP语法的中间语言，将代码编译为高性能的C扩展。zephir支持面向对象编程，变量类型除了类似PHP的动态类型，还支持静态类型（有点像FackBook的&lt;a class="link" href="http://hacklang.org/" target="_blank" rel="noopener"&#10; &gt;hack&lt;/a&gt;了）,而且可以调用php内置或其他C扩展的函数。zephir编译流程如下&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/scheme.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="scheme" class="gallery-image" data-flex-basis="660px" data-flex-grow="275" height="109" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/scheme-300x109.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;整个过程是zephir和底层编译器自动进行编译优化的，当然也可以自己&lt;a class="link" href="http://zephir-lang.com/optimizers.html" target="_blank" rel="noopener"&#10; &gt;调整&lt;/a&gt;以获得更好的性能。&lt;br&gt;&#10;在ubuntu下的安装如&lt;a class="link" href="http://zephir-lang.com/install.html" target="_blank" rel="noopener"&#10; &gt;官方教程&lt;/a&gt;即可，在centos下的安装&lt;a class="link" href="https://github.com/zekiunal/ZephirInstallationCentos/blob/master/zephir.sh" target="_blank" rel="noopener"&#10; &gt;如下&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;su -c &lt;span style="color:#e6db74"&gt;&amp;#39;yum update&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y wget &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y vim &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y libtool&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y gcc &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y make &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y re2c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y php55w &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y php55w-devel &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y php55w-json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo yum install -y git-core &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/json-c/json-c.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd json-c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./autogen.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/phalcon/zephir&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd zephir&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./install -c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zephir help&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装完成如下：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/zephir10.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="zephir10" class="gallery-image" data-flex-basis="297px" data-flex-grow="123" height="242" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/zephir10-300x242.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;按照教程创建示例：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zephir init utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim utils/greeting.zep&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;greeting.zep代码如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Utils&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Greeting&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;say&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hello world!&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译安装&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ zephir build&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，我在php5.3下面这么编译都不行，在php5.5/php5.4的版本基本没有碰到什么问题。&lt;br&gt;&#10;然后更改php.ini：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在php.ini中加上以下内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;zephir编译的扩展需要依赖json.so，需要提前加载&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[json]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;如果php.ini中没有则加上，有则去掉;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=json.so&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[utils]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=utils.so &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看php可用扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php -i&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：如果提示’undefined symbol: php_json_decode_ex in Unknown on line 0’，则是php json扩展未加载，在php.ini打开就行了。加载了json.so后又提示’PHP Warning: Module ‘json’ already loaded’，则是已经在其他地方加载了该扩展，找出并注释掉。我的是在php.d下面的json.ini里面：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim /etc/php.d/json.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[json]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;已经在php.ini中加载了，为避免重复加载注释掉&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;extension = json&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载成功后的效果：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/zephir3.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="zephir3" class="gallery-image" data-flex-basis="244px" data-flex-grow="102" height="294" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/zephir3-300x294.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;创建一个php脚本来试一下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~/utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo vim greeting.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;greeting.php代码如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Utils\Greeting&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;say&lt;/span&gt;(), &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存并运行：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/zephir11.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="zephir11" class="gallery-image" data-flex-basis="3130px" data-flex-grow="1304" height="23" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/zephir11-300x23.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/zephir5.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="zephir5" class="gallery-image" data-flex-basis="1014px" data-flex-grow="422" height="71" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/zephir5-300x71.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/zephir6.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="zephir6" class="gallery-image" data-flex-basis="947px" data-flex-grow="394" height="76" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/zephir6-300x76.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;至此你的zephir编译的扩展已经成功了，赶紧翻译你的PHP代码去吧。&lt;br&gt;&#10;参考这篇&lt;a class="link" href="http://www.pigo.idv.tw/archives/2641" target="_blank" rel="noopener"&#10; &gt;教程&lt;/a&gt;，计算斐波拉契数列在我的环境下是这样的：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/zephir13.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="zephir13" class="gallery-image" data-flex-basis="1636px" data-flex-grow="681" height="44" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/zephir13-300x44.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;性能提升还是挺明显的，而且在静态类型（强类型）下面还能比动态类型再提升。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.ideawu.net/blog/archives/828.html" target="_blank" rel="noopener"&#10; &gt;开源的 PHP 轻量级框架 iphp&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.imsiren.com/archives/572" target="_blank" rel="noopener"&#10; &gt;自己写PHP扩展之创建一个类&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/heiyeshuwu/article/details/3453854" target="_blank" rel="noopener"&#10; &gt;快速开发一个PHP扩展&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.shayanderson.com/linux/centos-5-or-centos-6-upgrade-php-to-php-54-or-php-55.htm" target="_blank" rel="noopener"&#10; &gt;CentOS 5 or CentOS 6 Upgrade PHP to PHP 5.4 or PHP 5.5&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.pigo.idv.tw/archives/2641" target="_blank" rel="noopener"&#10; &gt;PHP 開發者應該將 Zephir 列為重要觀察的專案&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://code.facebook.com/posts/264544830379293/hack-a-new-programming-language-for-hhvm/" target="_blank" rel="noopener"&#10; &gt;Hack: a new programming language for HHVM&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.php-cpp.com/" target="_blank" rel="noopener"&#10; &gt;PHP-CPP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.sitepoint.com/getting-started-php-extension-development-via-zephir/" target="_blank" rel="noopener"&#10; &gt;Getting Started with PHP Extension Development via Zephir&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.sitepoint.com/quick-tip-install-zephir-phalcon-2-vagrant/" target="_blank" rel="noopener"&#10; &gt;Quick Tip: Install Zephir and Phalcon 2 on Vagrant&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP 输出控制</title><link>https://courages.us/php-%E8%BE%93%E5%87%BA%E6%8E%A7%E5%88%B6/</link><pubDate>Sat, 02 May 2015 16:33:45 +0800</pubDate><guid>https://courages.us/php-%E8%BE%93%E5%87%BA%E6%8E%A7%E5%88%B6/</guid><description>&lt;p&gt;最近提交完代码后，发现Firephp在其他人的环境下又出问题了，提示：’Headers already sent　in …’，与上一次&lt;a class="link" href="https://courages.us/%e5%bc%80%e5%90%affirephp%e6%97%b6nginx-php-fpm%e4%b8%8b502%e9%94%99%e8%af%af%e8%a7%a3%e5%86%b3/" target="_blank" rel="noopener"&#10; &gt;Nginx 缓冲区超出&lt;/a&gt;不太一样。查看Nginx错误日志，并没有发现错误，并且有同学发现Apache下面也会，怀疑是PHP的问题。但是我用的也是Apache，并不会出现问题！偶然发现有一个页面不会出现错误提示，发现该页面输出内容大小在1KB左右，怀疑是&lt;a class="link" href="http://php.net/manual/en/outcontrol.configuration.php#ini.output-buffering" target="_blank" rel="noopener"&#10; &gt;PHP的输出缓冲区超出&lt;/a&gt;时，自动发送缓冲区数据，导致后续Firephp通过Http header发送调试信息失败了并结束php脚本执行。&lt;/p&gt;&#10;&lt;p&gt;注释掉模板渲染后的输出语句，不再提示该错误，确定是php的缓冲输出有问题。比较不同环境下的php.ini，发现output_buffering的值不太一样，我的值是On，而其他人则是默认值4096。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Output buffering is a mechanism for controlling how much output data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; (excluding headers and cookies) PHP should keep internally before pushing that&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; data to the client. If your application&amp;#39;s output exceeds this setting, PHP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; will send that data in chunks of roughly the size you specify.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Turning on this setting and managing its maximum buffer size can yield some&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; interesting side-effects depending on your application and web server.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; You may be able to send headers and cookies after you&amp;#39;ve already sent output&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; through print or echo. You also may see performance benefits if your server is&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; emitting less packets due to buffered output versus PHP streaming the output&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; as it gets it. On production servers, 4096 bytes is a good setting for performance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; reasons.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Note: Output buffering can also be controlled via Output Buffering Control&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; functions.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Possible Values:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; On = Enabled and buffer is unlimited. (Use with caution)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Off = Disabled&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Integer = Enables the buffer and sets its maximum size in bytes.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Note: This directive is hardcoded to Off for the CLI SAPI&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Default Value: Off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Development Value: 4096&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Production Value: 4096&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; http://php.net/output-buffering&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_buffering = On&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;根据上面的解释，当output_buffering为On或者4096时，在每次请求里面，当我们使用echo或print的时候，php实际上并不立即输出而是先保存到缓冲区里面去，当达到一定大小（如4KB）或脚本执行结束的时候，再向浏览器输出缓冲区内容并清空。&lt;/p&gt;&#10;&lt;p&gt;Http协议传输内容时，先传输响应头，一旦内容开始输出后，响应头不再可以改变。当output_buffering为On时，PHP会将所有的输出缓存起来，等待请求结束时在向浏览器输出内容，故Firephp在最后时刻更改Http响应头仍然不会存在问题，因为此时仍输出任何内容；当output_buffering为4096（或其他固定值）时，每次php缓冲区一满便会向客户端输出，此时已输出内容，响应头不再可以改变，若尝试设置header便会提示：’Headers already sent…’。&lt;/p&gt;&#10;&lt;p&gt;做好Webserver的缓冲输出控制，能够带来更好的用户体验，如&lt;a class="link" href="https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919" target="_blank" rel="noopener"&#10; &gt;Facebook&lt;/a&gt;、&lt;a class="link" href="http://www.slideshare.net/slawdan/bigpipe1126adev" target="_blank" rel="noopener"&#10; &gt;新浪&lt;/a&gt;的Bigpipe。&lt;/p&gt;&#10;&lt;p&gt;本次的问题排查发现，由于大部分页面的调试信息较多，导致Http响应头较大（远大于4KB，有的达到36KB），所以触发了自动输出机制。解决办法：更改output_buffering为On；在代码里面手动ob_start()；更改output_buffering为更大值；减少日志调试信息。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/en/book.outcontrol.php" target="_blank" rel="noopener"&#10; &gt;PHP Output Buffering Control&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.sitepoint.com/php-streaming-output-buffering-explained/" target="_blank" rel="noopener"&#10; &gt;PHP Streaming and Output Buffering Explained&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/2832010/what-is-output-buffering" target="_blank" rel="noopener"&#10; &gt;What is output buffering?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/flush" target="_blank" rel="noopener"&#10; &gt;php flush&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2011/02/13/1870.html" target="_blank" rel="noopener"&#10; &gt;加速PHP的ECHO&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919" target="_blank" rel="noopener"&#10; &gt;BigPipe: Pipelining web pages for high performance&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.slideshare.net/slawdan/bigpipe1126adev" target="_blank" rel="noopener"&#10; &gt;新浪微博的BigPipe后端实现技术分享&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.searchtb.com/2011/04/an-introduction-to-bigpipe.html" target="_blank" rel="noopener"&#10; &gt;BigPipe学习研究&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zh.wikipedia.org/wiki/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81" target="_blank" rel="noopener"&#10; &gt;分块传输编码&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP性能分析之xhprof</title><link>https://courages.us/php%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E4%B9%8Bxhprof/</link><pubDate>Thu, 30 Apr 2015 21:37:08 +0800</pubDate><guid>https://courages.us/php%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E4%B9%8Bxhprof/</guid><description>&lt;p&gt;&lt;a class="link" href="https://courages.us/linux%e4%b8%8b%e4%bd%bf%e7%94%a8xdebug%e5%88%86%e6%9e%90php%e7%a8%8b%e5%ba%8f/" target="_blank" rel="noopener"&#10; &gt;xdebug&lt;/a&gt;讲到了使用xdebug对php程序进行性能分析，这里再介绍另外一个工具：&lt;a class="link" href="https://github.com/phacility/xhprof" target="_blank" rel="noopener"&#10; &gt;xhprof&lt;/a&gt;，facebook出品。xhprof是一个函数级别的分层性能报告工具，包括调用次数，阻塞时间，CPU时间和内存使用情况。&lt;br&gt;&#10;首先，下载并安装&lt;a class="link" href="https://pecl.php.net/package/xhprof" target="_blank" rel="noopener"&#10; &gt;xhprof扩展&lt;/a&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -zxvf xhprof-0.9.4.tgz &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd xhprof-0.9.4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/php/bin/phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --with-php-config&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local/php/bin/php-config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#拷贝扩展&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xhprof.so /usr/local/php/lib/php/extensions/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p /tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod &lt;span style="color:#ae81ff"&gt;755&lt;/span&gt; /tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chown www:www /tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;xhprof自带的界面工具比较简单，这里推荐使用另外一个UI：&lt;a class="link" href="http://xhprof.io/" target="_blank" rel="noopener"&#10; &gt;XHProf.io&lt;/a&gt;。下载解压到web目录下面，重命名/xhprof/includes/目录下的config.inc.sample.php为/xhprof/includes/config.inc.php，并更改文件：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;url_base&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://192.168.84.2:8502/&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//本地的XHProf.io站点&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;url_static&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// When undefined, it defaults to $config[&amp;#39;url_base&amp;#39;] . &amp;#39;public/&amp;#39;. This should be absolute URL.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;pdo&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PDO&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;mysql:dbname=test;host=192.168.84.3;charset=utf8&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;//本地的数据库配置，只支持PDO&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在test数据库上运行/xhprof/setup/database.sql，创建性能检测相关的表结构。&lt;br&gt;&#10;由于XHProf会去github上检测版本，国内访问较慢，建议不要检测。更改/xhprof/includes/bootstrap.inc.php如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;curl_setopt_array&lt;/span&gt;($ch, &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;CURLOPT_URL&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://192.168.84.2:8502/version.json&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;//本地的XHProf.io站点下面&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;CURLOPT_HEADER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后更改php.ini配置，在最后加上以下内容：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;;xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[xhprof]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;extension=xhprof.so;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xhprof.output_dir=/tmp/xhprof&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Automatically add files before PHP document.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; XHProf.io站点下的prepend.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auto_prepend_file = /usr/local/nginx/xhprof/inc/prepend.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Automatically add files after PHP document.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; XHProf.io站点下的append.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auto_append_file = /usr/local/nginx/xhprof/inc/append.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;auto_prepend_file为每次php脚本运行前，自动加载并运行的文件；auto_append_file为每次php脚本运行后，自动加载并运行的文件。这样可以省去每次在需要检测的php文件里面写xhprof_enable/xhprof_disable等调用代码，不必更改原有代码（无侵入）。&lt;br&gt;&#10;注意：如果你访问了php页面却收集不到情况，可能是你的代码里面写了exit/die终止了程序执行，导致auto_append_file未加载执行，去掉exit/die就可以了。另外，如果提示：Unexpected system behaviour，可能是数据库连接不上，PDO、mbstring扩展未安装，响应数据里面带有错误信息的等等。&lt;/p&gt;&#10;&lt;p&gt;重启php-fpm：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#重启php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -USR2 &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat /usr/local/php/var/run/php-fpm.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof1" class="gallery-image" data-flex-basis="765px" data-flex-grow="319" height="94" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof1-300x94.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;访问该服务器上php页面，即可以在http://192.168.84.2:8502/看到检测情况。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof5.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof5" class="gallery-image" data-flex-basis="444px" data-flex-grow="185" height="162" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof5-300x162.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof4.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof4" class="gallery-image" data-flex-basis="441px" data-flex-grow="184" height="163" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof4-300x163.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xhprof6.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xhprof6" class="gallery-image" data-flex-basis="486px" data-flex-grow="202" height="148" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xhprof6-300x148.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参数说明&lt;br&gt;&#10;Inclusive Time 包括子函数所有执行时间。&lt;br&gt;&#10;Exclusive Time/Self Time 函数执行本身花费的时间，不包括子树执行时间。&lt;br&gt;&#10;Wall Time 花去了的时间或挂钟时间。&lt;br&gt;&#10;CPU Time 用户耗的时间+内核耗的时间&lt;br&gt;&#10;Inclusive CPU 包括子函数一起所占用的CPU&lt;br&gt;&#10;Exclusive CPU 函数自身所占用的CPU&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.snsgou.com/post-278.html" target="_blank" rel="noopener"&#10; &gt;给CentOS6.3 + PHP5.3 安装PHP性能测试工具 XHProf-0.9.2&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/gajus/xhprof.io/blob/master/INSTALL.md" target="_blank" rel="noopener"&#10; &gt;xhprof.io/INSTALL.md&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/ini.core.php#ini.auto-append-file" target="_blank" rel="noopener"&#10; &gt;php auto_append_file&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP性能分析之Xdebug</title><link>https://courages.us/linux%E4%B8%8B%E4%BD%BF%E7%94%A8xdebug%E5%88%86%E6%9E%90php%E7%A8%8B%E5%BA%8F/</link><pubDate>Tue, 28 Apr 2015 21:59:34 +0800</pubDate><guid>https://courages.us/linux%E4%B8%8B%E4%BD%BF%E7%94%A8xdebug%E5%88%86%E6%9E%90php%E7%A8%8B%E5%BA%8F/</guid><description>&lt;p&gt;最近一个PHP程序性能跑的不行，于是又想起来Xdebug这个扩展，并记录一下。&lt;br&gt;&#10;首先去&lt;a class="link" href="http://xdebug.org/download.php" title="xdebug"&#10; target="_blank" rel="noopener"&#10; &gt;Xdebug官网&lt;/a&gt;下载源码包，注意下载对应版本的源码包，我的环境是PHP 5.4.9，安装了最新的Xdebug 2.3.2后，不能使用&lt;a class="link" href="http://sourceforge.net/projects/wincachegrind/" title="wincachegrind"&#10; target="_blank" rel="noopener"&#10; &gt;WinCacheGrind&lt;/a&gt;和&lt;a class="link" href="https://code.google.com/p/webgrind/" title="webgrind"&#10; target="_blank" rel="noopener"&#10; &gt;WebGrind&lt;/a&gt;进行分析，又重新下载了旧的Xdebug 2.2.0。&lt;br&gt;&#10;然后在Centos下面编译安装&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tar -zxvf xdebug-2.2.0.tgz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd xdebug-2.2.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/php/bin/phpize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --enable-xdebug --with-php-config&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local/php/bin/php-config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译安装完成后是这样子的&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xdebug.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xdebug" class="gallery-image" data-flex-basis="533px" data-flex-grow="222" height="135" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xdebug-300x135.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;将xdebug扩展复制到php的扩展目录下，并创建/tmp/xdebug文件。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so /usr/local/php/lib/php/extensions/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p /tmp/xdebug&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod &lt;span style="color:#ae81ff"&gt;755&lt;/span&gt; /tmp/xdebug&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chown www:www /tmp/xdebug&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;并更改php.ini如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; XDEBUG Extension&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zend_extension = &amp;#34;/usr/local/php/lib/php/extensions/xdebug.so&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[xdebug]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xdebug.profiler_enable = on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xdebug.trace_output_dir=&amp;#34;/tmp/xdebug&amp;#34; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xdebug.profiler_output_dir=&amp;#34;/tmp/xdebug&amp;#34; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xdebug.profiler_output_name = cachegrind.out.%t.%p&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后需要重启php-fpm，使配置生效。&lt;/p&gt;&#10;&lt;p&gt;这个环境下并没有php-fpm的pid文件，每次重启需要查找进程pid，于是先生成下。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#查找进程id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ps aux | grep php-fpm &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#结束进程&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill &lt;span style="color:#ae81ff"&gt;6369&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑/usr/local/php/etc/php-fpm.conf如下，去掉注释&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[global]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Pid file&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Note: the default prefix is /usr/local/php/var&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;; Default Value: none&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pid = run/php-fpm.pid&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后启动php-fpm&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#启动php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/php/sbin/php-fpm -c /usr/local/php/lib/php.ini -y /usr/local/php/etc/php-fpm.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以后就可以方便的重启php-fpm了。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#关闭php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -INT &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat /usr/local/php/var/run/php-fpm.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#重启php-fpm&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -USR2 &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat /usr/local/php/var/run/php-fpm.pid&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启完成后，查看phpinfo，Xdebug是否加载成功。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xdebug2.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xdebug2" class="gallery-image" data-flex-basis="303px" data-flex-grow="126" height="237" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xdebug2-300x237.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;运行php程序就会在/tmp/xdebug目录下，生成对应的profile文件（cachegrind.out.%t.%p），这里可以使用&lt;a class="link" href="http://sourceforge.net/projects/wincachegrind/" title="windcachegrind"&#10; target="_blank" rel="noopener"&#10; &gt;WinCacheGrind&lt;/a&gt;或&lt;a class="link" href="https://code.google.com/p/webgrind/" title="webgrind"&#10; target="_blank" rel="noopener"&#10; &gt;WebGrind&lt;/a&gt;进行分析。&lt;br&gt;&#10;Windows下面使用WinCacheGrind进行分析，可以查看PHP执行流程，函数调用次数、耗时。双击列表可以进入详细调用情况。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xdebug3.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xdebug3" class="gallery-image" data-flex-basis="615px" data-flex-grow="256" height="117" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xdebug3-300x117.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xdebug6.bmp" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xdebug6" class="gallery-image" data-flex-basis="434px" data-flex-grow="181" height="476" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xdebug6.bmp" srcset="https://courages.us/xdebug6_14024625835632333654_hu_79d4b6eb7243ef17.bmp 800w, https://courages.us/wp-content/uploads/2015/04/xdebug6.bmp 862w" width="862"&gt;&lt;/a&gt;&lt;br&gt;&#10;WebGrind程序部署在安装Xdebug的服务器上即可，会显示已经生成的profile文件，下拉选择进行分析。也可以查看PHP执行流程，函数调用次数、耗时。点击小三角会展开调用栈，后面跟着源码位置，可直接定位查看代码。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/04/xdebug4.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="xdebug4" class="gallery-image" data-flex-basis="489px" data-flex-grow="204" height="147" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/04/xdebug4-300x147.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.searchtb.com/2010/12/using-xdebug-to-improve-performance.html" title="前端开发中的性能那点事（一）巧用xdebug"&#10; target="_blank" rel="noopener"&#10; &gt;前端开发中的性能那点事（一）巧用xdebug&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zyan.cc/post/257/" title="利用Xdebug分析PHP程序，找出性能瓶颈[原创]"&#10; target="_blank" rel="noopener"&#10; &gt;利用Xdebug分析PHP程序，找出性能瓶颈[原创]&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.4wei.cn/archives/1002061" title="php-fpm - 启动参数及重要配置详解"&#10; target="_blank" rel="noopener"&#10; &gt;php-fpm – 启动参数及重要配置详解&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>使用PC控制android手机</title><link>https://courages.us/%E7%94%A8%E7%94%B5%E8%84%91%E6%8E%A7%E5%88%B6android%E6%89%8B%E6%9C%BA/</link><pubDate>Tue, 31 Mar 2015 21:03:25 +0800</pubDate><guid>https://courages.us/%E7%94%A8%E7%94%B5%E8%84%91%E6%8E%A7%E5%88%B6android%E6%89%8B%E6%9C%BA/</guid><description>&lt;p&gt;跑步的时候不小心把手机屏幕摔裂了，操作不了。在等待新手机的时候，又没有其他手机可以用。于是想用电脑来控制手机，这里推荐一个软件&lt;a class="link" href="http://tc.sigma-rt.com.cn/index.php" title="Total Control"&#10; target="_blank" rel="noopener"&#10; &gt;Total Control&lt;/a&gt;，可以在用鼠标代替手指操作手机，也可以用于手机截屏、演示等。&lt;/p&gt;&#10;&lt;p&gt;首先到&lt;a class="link" href="http://tc.sigma-rt.com.cn/index.php" target="_blank" rel="noopener"&#10; &gt;官网下载&lt;/a&gt;Total Control 最新的PC版软件。安装时会提示下载&lt;a class="link" href="http://www.java.com/zh_CN/" title="java"&#10; target="_blank" rel="noopener"&#10; &gt;Java&lt;/a&gt;环境，安装完Java后，可以开始安装Total Control了。&lt;/p&gt;&#10;&lt;p&gt;Total Control通过USB连接手机需要驱动，这里推荐一个懒人方法：通过&lt;a class="link" href="http://www.wandoujia.com/" title="豌豆荚"&#10; target="_blank" rel="noopener"&#10; &gt;豌豆荚&lt;/a&gt;自动识别你的手机并安装驱动，然后Total Control也可以连接手机了，会自动安装Total Control手机端 ，然后就可以开始玩了。&lt;/p&gt;&#10;&lt;p&gt;更新：发现另外一个PC控制手机的软件&lt;a class="link" href="http://www.iplaysoft.com/teamviewer-quicksupport.html" target="_blank" rel="noopener"&#10; &gt;Teamviewer QuickSupport&lt;/a&gt;，通过网络来控制。（需root，不需驱动）&lt;/p&gt;&#10;&lt;p&gt;一些截图：&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/03/tc3.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="连接手机" class="gallery-image" data-flex-basis="356px" data-flex-grow="148" height="202" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/03/tc3-300x202.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/03/tc1.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="连接成功" class="gallery-image" data-flex-basis="137px" data-flex-grow="57" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/03/tc1-172x300.png" width="172"&gt;&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/03/tc2.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="手机演示" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="169" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/03/tc2-300x169.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://club.tech.163.com/bbs/mobile_a2ox/301774877.html" title="PC端控制android手机"&#10; target="_blank" rel="noopener"&#10; &gt;PC端控制android手机&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://tc.sigma-rt.com.cn/index.php" title="Total Control-帮助你的电脑控制手机"&#10; target="_blank" rel="noopener"&#10; &gt;Total Control-帮助你电脑控制手机&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP unserialize出错</title><link>https://courages.us/php-unserialize%E5%87%BA%E9%94%99/</link><pubDate>Sun, 12 Oct 2014 17:03:15 +0800</pubDate><guid>https://courages.us/php-unserialize%E5%87%BA%E9%94%99/</guid><description>&lt;p&gt;最近碰到一个问题，在使用PHP的unserialize函数反序列化服务端传递过来的参数时报错了：unserialize() [function.unserialize]: Error at offset 180 of 181 bytes。最后在Stackoverflow上找到了一个非常好的&lt;a class="link" href="http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset" target="_blank" rel="noopener"&#10; &gt;答案&lt;/a&gt;：这是由于序列化时字符串长度算错了导致的。作者还写了个校正长度的正则表达式，提供了一个用于计算序列化是否出错了的函数。导致序列化出错的原因通常是因为内容使用了双引号（”）而不是单引号（’），php与mysql编码不一致（UTF8），内容包括冒号（:）和引号（;）也会导致反序列化出错。&lt;br&gt;&#10;解决的方法是在serialize上加上base64函数，对数据做base64编码和解码：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$toDatabse &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;base64_encode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;serialize&lt;/span&gt;($data));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$fromDatabase &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;unserialize&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;base64_decode&lt;/span&gt;($data)); &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当然更建议使用json_encode和json_decode的来处理数据的序列化和反序列化会更快，但有一些局限性&lt;a class="link" href="http://stackoverflow.com/questions/804045/preferred-method-to-store-php-arrays-json-encode-vs-serialize" target="_blank" rel="noopener"&#10; &gt;（这里）&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://courages.us/php-base64_decode-%e7%a9%ba%e6%a0%bc%e9%97%ae%e9%a2%98/" target="_blank" rel="noopener"&#10; &gt;之前&lt;/a&gt;有碰到URL参数传递时base64_encode/base64_decode的坑，可以像下面这样处理：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;base64url_encode&lt;/span&gt;($s) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str_replace&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;base64_encode&lt;/span&gt;($s));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;base64url_decode&lt;/span&gt;($s) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;base64_decode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;str_replace&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;), $s));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset" target="_blank" rel="noopener"&#10; &gt;unserialize() [function.unserialize]: Error at offset&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://davidwalsh.name/php-serialize-unserialize-issues" target="_blank" rel="noopener"&#10; &gt;PHP Serialize() &amp;amp; Unserialize() Issues&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.jackreichert.com/2014/02/02/handling-a-php-unserialize-offset-error/" target="_blank" rel="noopener"&#10; &gt;Handling a PHP unserialize offset error… and why it happens&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.vidalquevedo.com/php-safely-serialize-and-unserialze-arrays" target="_blank" rel="noopener"&#10; &gt;PHP – Safely serialize and unserialze arrays&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/11449577/why-is-base64-encode-adding-a-slash-in-the-result" target="_blank" rel="noopener"&#10; &gt;Why is base64_encode() adding a slash “/” in the result?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/804045/preferred-method-to-store-php-arrays-json-encode-vs-serialize" target="_blank" rel="noopener"&#10; &gt;d&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Mysql INT和CHAR类型的隐式转换</title><link>https://courages.us/mysql-int%E5%92%8Cchar%E7%B1%BB%E5%9E%8B%E7%9A%84%E9%9A%90%E5%BC%8F%E8%BD%AC%E6%8D%A2/</link><pubDate>Sat, 23 Aug 2014 22:09:47 +0800</pubDate><guid>https://courages.us/mysql-int%E5%92%8Cchar%E7%B1%BB%E5%9E%8B%E7%9A%84%E9%9A%90%E5%BC%8F%E8%BD%AC%E6%8D%A2/</guid><description>&lt;p&gt;最近碰到一个问题，由于没有对参数进行过滤和转换，直接拿到mysql里面进行查询了，大概是这样的：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; store &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;1}&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; store &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;{1}&amp;#39;&lt;/span&gt;;&lt;span style="color:#f92672"&gt;#&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;测试&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是前者仍然可以查出id为1的记录，后者是不行。知道mysql有隐式转换却不知道具体是怎么样的。google了下，发现隐式转换还有其他的问题，例如:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; store &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; store &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;前者将会查询出所有的记录，而后者只会匹配name值为0的记录。&lt;br&gt;&#10;总结了一下大概是这些大概是以下的原因：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;当查询字段是INT类型，如果查询条件为CHAR，将查询条件转换为INT，如果是字符串前导都是数字将会进行截取，如果不是转换为0。&lt;/li&gt;&#10;&lt;li&gt;当查询字段是CHAR类型，如果查询条件为INT，将查询字段为换为INT再进行比较，可能会造成全表扫描。示例2的name字段为CHAR类型，第一句查询转换为INT时都等于0，所以全部匹配了；第二句查询同为CHAR类型不发生转换，所以仅匹配值为0的记录。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;mysql的隐式转换还有很多&lt;a class="link" href="http://www.hustdba.com/?p=145" target="_blank" rel="noopener"&#10; &gt;其他的坑&lt;/a&gt;，所以一定要指明查询条件类型，不要让mysql去做自动转换。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.eood.cn/mysql_params" target="_blank" rel="noopener"&#10; &gt;价值百万的 MySQL 的隐式类型转换&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://hi.baidu.com/315058122/item/83bac5b97784747f254b09d5" target="_blank" rel="noopener"&#10; &gt;mysql字符串的隐式转换导致数据库操作异常&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/lidan3959/article/details/21653149" target="_blank" rel="noopener"&#10; &gt;关于mysql 隐式转换的一个小问题&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.zhihu.com/question/20162439" target="_blank" rel="noopener"&#10; &gt;MySQL查询类型不正确不使用索引？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.javaranger.com/archives/1098" target="_blank" rel="noopener"&#10; &gt;mysql的隐式的数据类型转换&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.hustdba.com/?p=145" target="_blank" rel="noopener"&#10; &gt;MySQL隐式转换之坑&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dev.mysql.com/doc/refman/5.1/zh/column-types.html" target="_blank" rel="noopener"&#10; &gt;列类型&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>开启Firephp时Nginx PHP-FPM下502错误解决</title><link>https://courages.us/%E5%BC%80%E5%90%AFfirephp%E6%97%B6nginx-php-fpm%E4%B8%8B502%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3/</link><pubDate>Sun, 03 Aug 2014 10:53:25 +0800</pubDate><guid>https://courages.us/%E5%BC%80%E5%90%AFfirephp%E6%97%B6nginx-php-fpm%E4%B8%8B502%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3/</guid><description>&lt;p&gt;在自己的电脑上调试的好好的，部署到Linux Nginx环境的时候却发现有些PHP页面在Firefox下面会返回502，在IE下面却是正常的，甚至在chrome下面也会出现502。顺着Nginx，Firefox这两个关键字，终于找到原因：原来是开启Firephp(chrome装了webug)时，Firephp的调试信息会写入的请求头里面，导致Nginx的FastCGI缓冲区超出，从而返回502。在自己的电脑上之所以不会是因为使用的是Apache。&lt;br&gt;&#10;于是顺着其他人的解答修改了nginx.conf中fastcig相关的参数：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_buffer_size 1024k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_buffers &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 512k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_busy_buffers_size 1024k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fastcgi_temp_file_write_size 1024k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一开始这些参数是256，后来改成了512还是有部分页面会出现502，再改成1024终于好了。&lt;/p&gt;&#10;&lt;p&gt;检查Nginx的配置文件，并重启：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@webserver sbin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./nginx -t&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@webserver sbin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# ./nginx -s reload&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@webserver sbin&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://serverfault.com/questions/201632/nginx-php5-fpm-repeated-cut-outs-502" target="_blank" rel="noopener"&#10; &gt;Nginx + PHP5-FPM repeated cut outs 502&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://shiki.me/blog/firephp-on-nginx-502-bad-gateway/" target="_blank" rel="noopener"&#10; &gt;FirePHP on Nginx: 502 Bad Gateway&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://britg.com/2009/06/16/nginx-proxies-with-firephp/" target="_blank" rel="noopener"&#10; &gt;Nginx Proxies with FirePHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://letle.iteye.com/blog/1049265" target="_blank" rel="noopener"&#10; &gt;Nginx提示502和504错误的终极解决方案&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.howtocn.org/nginx:nginx%E6%A8%A1%E5%9D%97%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88:standardhttpmodules:fastcgi" target="_blank" rel="noopener"&#10; &gt;FastCGI模块（FastCGI）&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Windows 8 安装Vagrant和VirtualBox</title><link>https://courages.us/windows-8-%E5%AE%89%E8%A3%85vagrant%E5%92%8Cvirtualbox/</link><pubDate>Wed, 23 Jul 2014 22:12:45 +0800</pubDate><guid>https://courages.us/windows-8-%E5%AE%89%E8%A3%85vagrant%E5%92%8Cvirtualbox/</guid><description>&lt;p&gt;由于php的一些扩展只有在linux下面才能用，就算是Cygwin下面也不行，例如pcntl。所以就决定安装一个linux虚拟机来作为开发环境，顺带找到了另外一个东西：&lt;a class="link" href="http://www.vagrantup.com/" target="_blank" rel="noopener"&#10; &gt;Vagrant&lt;/a&gt;。Vagrant作为一款虚拟机环境统一配置管理工具，后端可以是&lt;a class="link" href="https://www.virtualbox.org/" target="_blank" rel="noopener"&#10; &gt;VirtualBox&lt;/a&gt;，VMWare，AWS。这样当运行环境配置完了可以方便的部署在其他机器上或给予其他开发人员，实现配置一次，到处运行的功能。当使用Vagrant管理VirtualBox是运行在命令行下面的，而不需要打开界面。&lt;/p&gt;&#10;&lt;p&gt;首先，安装VirtualBox，&lt;a class="link" href="https://www.virtualbox.org/wiki/Downloads" target="_blank" rel="noopener"&#10; &gt;地址&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;然后，安装Vagrant，&lt;a class="link" href="http://www.vagrantup.com/downloads.html" target="_blank" rel="noopener"&#10; &gt;地址&lt;/a&gt;。安装完成后，将Vagrant的bin目录添加到系统的环境变量Path里面。&lt;/p&gt;&#10;&lt;p&gt;再然后，下载做好的虚拟机镜像，&lt;a class="link" href="http://www.vagrantbox.es/" target="_blank" rel="noopener"&#10; &gt;地址&lt;/a&gt;。我这里下载的是Ubuntu precise 64 VirtualBox，对应链接：http://files.vagrantup.com/precise64.box。这个镜像的下载速度还不错，centos的就不怎么样了，但还是建议先下载到本地硬盘在加载进来。&lt;/p&gt;&#10;&lt;p&gt;这时候应该先为这个虚拟机（Ubuntu precise 64）建一个目录，以便初始化和管理这个虚拟机主机。如果有多个虚拟机的话，就分别建立不同的目录来初始化。比如：E:\project\vagrant\dev。然后就在这个目录下面初始化这个镜像。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;E:&lt;span style="color:#ae81ff"&gt;\p&lt;/span&gt;roject&lt;span style="color:#ae81ff"&gt;\v&lt;/span&gt;agrant&lt;span style="color:#ae81ff"&gt;\d&lt;/span&gt;ev&amp;gt;vagrant box add Ubuntu12.04x64 &lt;span style="color:#e6db74"&gt;&amp;#34;file:///f:\box\precise64.box&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，file后面应该是三个/而不是两个。add后面跟的是这个虚拟机的名称，也可以用base自动识别。&lt;br&gt;&#10;打开对应目录下面的配置文件Vagrantfile，配置虚拟机的ip和共享目录。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config.vm.network &lt;span style="color:#e6db74"&gt;&amp;#34;private_network&amp;#34;&lt;/span&gt;, ip: &lt;span style="color:#e6db74"&gt;&amp;#34;192.168.33.10&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; config.vm.synced_folder &lt;span style="color:#e6db74"&gt;&amp;#34;E:/wamp/www&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/home/vagrant/www&amp;#34;&lt;/span&gt;　&lt;span style="color:#75715e"&gt;#将前者映射到后者&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;初始化并启动：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;E:&lt;span style="color:#ae81ff"&gt;\p&lt;/span&gt;roject&lt;span style="color:#ae81ff"&gt;\v&lt;/span&gt;agrant&lt;span style="color:#ae81ff"&gt;\d&lt;/span&gt;ev&amp;gt;vagrant init Ubuntu12.04x64&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;E:&lt;span style="color:#ae81ff"&gt;\p&lt;/span&gt;roject&lt;span style="color:#ae81ff"&gt;\v&lt;/span&gt;agrant&lt;span style="color:#ae81ff"&gt;\d&lt;/span&gt;ev&amp;gt;vagrant up&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img alt="vagrant up" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/s3.homezz.com/201407/4966/46661_o.png"&gt;&lt;br&gt;&#10;然后可以通过ssh连接上去管理了，这里使用Cygwin下面的&lt;a class="link" href="https://courages.us/cygwin-%e5%ae%89%e8%a3%85/" target="_blank" rel="noopener"&#10; &gt;ssh客户端&lt;/a&gt;，默认用户和密码都是vagrant。&lt;br&gt;&#10;&lt;img alt="vagrant ssh" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/s3.homezz.com/201407/4966/46660_o.png"&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get update &lt;span style="color:#75715e"&gt;#先更新下软件包，要不然有的可能会装不上&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意启动和连接虚拟机都需要切换到该虚拟机所在开发目录。还有一些其他的命令。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant init &lt;span style="color:#75715e"&gt;# 初始化&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant up &lt;span style="color:#75715e"&gt;# 启动虚拟机&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant halt &lt;span style="color:#75715e"&gt;# 关闭虚拟机&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant reload &lt;span style="color:#75715e"&gt;# 重启虚拟机&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant ssh &lt;span style="color:#75715e"&gt;# SSH 至虚拟机&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant status &lt;span style="color:#75715e"&gt;# 查看虚拟机运行状态&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant destroy &lt;span style="color:#75715e"&gt;# 销毁当前虚拟机&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vagrant package &lt;span style="color:#75715e"&gt;# 导出当前虚拟机&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有别人推荐的一个小软件win-sshfs，可以将Linux的目录直接mount到Windows系统上作为一个根盘符。注意：这是个32位软件，可能会安装不成功，需要采用兼容模式。&lt;br&gt;&#10;&lt;a class="link" href="https://courages.us/wp-content/uploads/2015/05/sshfs.png" target="_blank" rel="noopener"&#10; &gt;&lt;img alt="sshfs" class="gallery-image" data-flex-basis="385px" data-flex-grow="160" height="187" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/2015/05/sshfs-300x187.png" width="300"&gt;&lt;/a&gt;&lt;br&gt;&#10;然后就可以在我的电脑里面像本地文件一样管理。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.segmentfault.com/fenbox/1190000000264347" target="_blank" rel="noopener"&#10; &gt;使用 Vagrant 打造跨平台开发环境&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://kiwik.github.io/openstack/2013/12/22/%E4%BD%BF%E7%94%A8Vagrant%E5%92%8Cwin-sshfs%E6%94%AF%E6%8C%81OpenStack%E5%BC%80%E5%8F%91/" target="_blank" rel="noopener"&#10; &gt;使用vagrant和win Sshfs支持openstack开发&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/astaxie/Go-in-Action/blob/master/ebook/zh/01.2.md" target="_blank" rel="noopener"&#10; &gt;Vagrant安装配置&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://windrocblog.sinaapp.com/?p=1145" target="_blank" rel="noopener"&#10; &gt;Windows 7使用Vagrant构建虚拟开发环境&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://chenpeng.info/html/1951" target="_blank" rel="noopener"&#10; &gt;Vagrant+VirtualBox搭建统一开发环境&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Cygwin 安装</title><link>https://courages.us/cygwin-%E5%AE%89%E8%A3%85/</link><pubDate>Wed, 23 Jul 2014 20:40:01 +0800</pubDate><guid>https://courages.us/cygwin-%E5%AE%89%E8%A3%85/</guid><description>&lt;p&gt;在windows 8.1上安装&lt;a class="link" href="https://www.cygwin.com/" target="_blank" rel="noopener"&#10; &gt;Cygwin&lt;/a&gt;真的是非常蛋疼，网络一会儿就会自己停了，只能取消重试。为了装上php，找到了一个好东西：&lt;a class="link" href="http://zengrong.net/post/1792.htm" target="_blank" rel="noopener"&#10; &gt;apt-cyg&lt;/a&gt;，Cygwin的包管理器，有点像ubuntu的apt-get，强烈推荐。&lt;br&gt;&#10;安装apt-cyg很简单，但是国内访问googlecode非常不方便，这里提供一个&lt;a class="link" href="https://courages.us/wp-content/uploads/2014/07/apt-cyg.rar" target="_blank" rel="noopener"&#10; &gt;下载链接&lt;/a&gt;（注意：githut上的&lt;a class="link" href="https://github.com/transcode-open/apt-cyg" target="_blank" rel="noopener"&#10; &gt;这个链接&lt;/a&gt;跟&lt;a class="link" href="htpp://code.google.com/p/apt-cyg" &gt;googlecode&lt;/a&gt;上不一样的）．&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget https://courages.us/wp-content/uploads/2014/07/apt-cyg.rar&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x apt-cyg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mv apt-cyg /usr/local/bin/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就可以用了，例如查找包，安装包，指定源。这里也推荐下另外一个cygwinports（ftp://ftp.cygwinports.org/pub/cygwinports），当你找不你想要的就可以来这里找。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt-cyg -m ftp://ftp.cygwinports.org/pub/cygwinports find php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt-cyg -m http://mirrors.163.com/cygwin find openssl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt-cyg install openssl&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img alt="apt-cyg" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;br&gt;&#10;安装完成后就可以使用ssh了。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="htpp://code.google.com/p/apt-cyg" &gt;apt-cyg&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zengrong.net/post/1792.htm" target="_blank" rel="noopener"&#10; &gt;CYGWIN的包管理器：APT-CYG&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zengrong.net/post/2048.htm" target="_blank" rel="noopener"&#10; &gt;CYGWIN在WINDOWS8.1上的CHMOD无法修改权限&lt;/a&gt;&lt;/p&gt;</description></item><item><title>真正的喜欢是不会那么容易放弃的</title><link>https://courages.us/%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%96%9C%E6%AC%A2%E6%98%AF%E4%B8%8D%E4%BC%9A%E9%82%A3%E4%B9%88%E5%AE%B9%E6%98%93%E6%94%BE%E5%BC%83%E7%9A%84/</link><pubDate>Sun, 02 Mar 2014 21:27:14 +0800</pubDate><guid>https://courages.us/%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%96%9C%E6%AC%A2%E6%98%AF%E4%B8%8D%E4%BC%9A%E9%82%A3%E4%B9%88%E5%AE%B9%E6%98%93%E6%94%BE%E5%BC%83%E7%9A%84/</guid><description>&lt;p&gt;真正的喜欢是不会那么容易放弃的，再次记录下，以免找不到。来自&lt;a class="link" href="http://site.douban.com/106407/widget/notes/335509/note/157592419/" target="_blank" rel="noopener"&#10; &gt;这里&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/s1.homezz.com/201403/4966/43686_o.jpg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/s1.homezz.com/201403/4966/43688_o.jpg"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;a class="link" href="https://courages.us/wp-content/uploads/external/image-unavailable.svg" &gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://courages.us/wp-content/uploads/external/image-unavailable.svg"&gt;&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;作者：家训&lt;/p&gt;</description></item><item><title>PHP 和 Mysql 日期问题</title><link>https://courages.us/php-%E5%92%8C-mysql-%E6%97%A5%E6%9C%9F%E9%97%AE%E9%A2%98/</link><pubDate>Thu, 22 Aug 2013 22:10:17 +0800</pubDate><guid>https://courages.us/php-%E5%92%8C-mysql-%E6%97%A5%E6%9C%9F%E9%97%AE%E9%A2%98/</guid><description>&lt;p&gt;最近在php 和 mysql上碰到了一个计算日期Bug：在mysql中使用date_add计算日期，比如date_add(now(),interval 30 year)，然后保存进去的值就变成了’0000-00-00 00:00:00’；在php 中使用strtotime计算日期，比如(‘2143-08-22 15:23:56 -100 year’)，然后格式化后就变成了’1970-01-01 ‘。后来google了下，发现这是著名的&lt;a class="link" href="http://zh.wikipedia.org/wiki/2038%E5%B9%B4%E9%97%AE%E9%A2%98" target="_blank" rel="noopener"&#10; &gt;2038年问题&lt;/a&gt;。&lt;br&gt;&#10;这个问题是因为在32位操作系统上日期类型是一个有正负号的32位整数，2147483647 是能表示的最大32为正整数，对应2038-01-19 03:14:07，超出了就“绕回”，所以不能正常处理。&lt;/p&gt;&#10;&lt;p&gt;怎么解决这个问题呢？使用64位的操作系统，这样子日期类型宽度就有64位了，能表示的日期就更大了。但是目前仍然有大量的程序运行在32为操作系统上，在php和mysql中要怎么处理呢？&lt;br&gt;&#10;在php中就不能使用strtotime来转换时间，因为它可能超出了。正确应该是用DateTime来处理时间。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$end&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DateTime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;now&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$end&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;modify&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;20&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $end&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y-m-d&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$to&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DateTime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;2100-08-22 21:40:00&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$interval&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$end&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;diff&lt;/span&gt;($to);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $interval&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;%R%y 年&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在mysql中应该使用datetime来保存超过2038年的日期。timestamp和datetime的区别是:&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;datetime类型能够保存从1000-01-01 00:00:00至9999-12-31 23:59:59；timestamp只能保存从1970-01-01 00:00:01至2038-01-19 03:14:07。timestamp的保存范围小，在2038-01-19 03:14:07过后将会溢出，而datetime则不会。&lt;/p&gt;&#10;&lt;p&gt;timestamp是一个时间戳，能够使用CURRENT_TIMESTAMP来进行填充，而datetime则不行。&lt;/p&gt;&#10;&lt;p&gt;timestamp是跟时区相关的，在改变时区后，保存的值也会做相应的改变。而datetime保存的值是不会因为时区改变而改变。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;所以如果要保存日期超过2038年的就选择datetime类型，如果是想在做update/inset是做一个自动日期记录而不关心日期的加减就选择timestamp。&lt;/p&gt;&#10;&lt;p&gt;参考链接&lt;br&gt;&#10;&lt;a class="link" href="http://zh.wikipedia.org/wiki/2038%E5%B9%B4%E9%97%AE%E9%A2%98" target="_blank" rel="noopener"&#10; &gt;2038年问题&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/2012589/php-mysql-year-2038-bug-what-is-it-how-to-solve-it" target="_blank" rel="noopener"&#10; &gt;PHP &amp;amp; mySQL: Year 2038 Bug: What is it? How to solve it?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.php.net/manual/zh/book.datetime.php" target="_blank" rel="noopener"&#10; &gt;PHP Date and Time&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/3266077/php-strtotime-is-returning-false-for-a-future-date" target="_blank" rel="noopener"&#10; &gt;PHP: strtotime is returning false for a future date?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://dev.mysql.com/doc/refman/5.0/en/datetime.html" target="_blank" rel="noopener"&#10; &gt;Mysql DATE, DATETIME, and TIMESTAMP Types&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://segmentfault.com/q/1010000000121702" target="_blank" rel="noopener"&#10; &gt;Mysql时间字段格式如何选择，TIMESTAMP，DATETIME，INT？&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://programmers.stackexchange.com/questions/126208/datetime-vs-timestamp-in-mysql-and-php-in-practice" target="_blank" rel="noopener"&#10; &gt;Datetime vs Timestamp in MySQL and PHP in practice?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP __destruct函数</title><link>https://courages.us/php-__destruct%E5%87%BD%E6%95%B0/</link><pubDate>Sun, 04 Aug 2013 22:34:24 +0800</pubDate><guid>https://courages.us/php-__destruct%E5%87%BD%E6%95%B0/</guid><description>&lt;p&gt;PHP引擎会在脚本执行完成后进行垃圾回收，那么是否还需要destruct呢？在stackoverflow上看到的一个很好的&lt;a class="link" href="http://stackoverflow.com/questions/7240230/is-the-destruct-method-necessary-for-php" target="_blank" rel="noopener"&#10; &gt;答复&lt;/a&gt;：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;析构函数本身跟内存释放没有任何直接的关系，它只是当一个对象被回收时执行自定义代码的“钩子”。它的作用跟构造函数刚好相反-构造函数本身也不申请内存（内存的申请和释放都是GC的事）。&lt;br&gt;&#10;GC能够很好的管理PHP原生的资源（比如对象），但是对于外部资源却必须手动处理。比如，一个文件管理的类，析构函数的作用就是保证如果文件被打开了，就应该被关闭。虽然“最好”在一个对象上要求去调用一个关闭或处理操作，这时析构函数就作为一种援助机制。&lt;br&gt;&#10;我本身反对将析构函数与GC一起使用。有许多微妙的问题他们可以引入如明显的非确定性和意外的能力保持对象存活——甚至在像PHP这种使用引用计数的语言里面。（Java/JVM和.net使用终结器更为挑剔。）&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;总结下，就是析构函数本身跟垃圾回收没有什么关系，但它应该用来确保一些外部资源被关闭，比如文件操作和数据库连接。&lt;br&gt;&#10;在一个项目中，我们可能只会使用一个数据库连接类，但是我们又不能随时关闭它，因为不能确定其他的地方是否有用到，那么就在析构函数里确保它关闭，否则PHP也不会手动去释放它，否则可能会经常遇到Mysql达到最大连接数的问题。为什么需要手动去释放资源呢？可以参阅鸟哥的&lt;a class="link" href="http://www.laruence.com/2012/07/25/2662.html" target="_blank" rel="noopener"&#10; &gt;文章&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/7240230/is-the-destruct-method-necessary-for-php" target="_blank" rel="noopener"&#10; &gt;Is the __destruct method necessary for PHP?&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2012/07/25/2662.html" target="_blank" rel="noopener"&#10; &gt;请手动释放你的资源(Please release resources manually)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://hi.baidu.com/hy0kl/item/28a688cbc775d03f459416c6" target="_blank" rel="noopener"&#10; &gt;[原创] 从 PHP 代码分析 PHP 的 GC(垃圾回收) 机制&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.php.net/manual/zh/features.gc.php" target="_blank" rel="noopener"&#10; &gt;PHP 垃圾回收机制&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Jquery 滚轮事件</title><link>https://courages.us/jquery-%E6%BB%9A%E8%BD%AE%E4%BA%8B%E4%BB%B6/</link><pubDate>Thu, 01 Aug 2013 22:44:52 +0800</pubDate><guid>https://courages.us/jquery-%E6%BB%9A%E8%BD%AE%E4%BA%8B%E4%BB%B6/</guid><description>&lt;p&gt;在项目中有采用到一个下拉列表插件&lt;a class="link" href="https://code.google.com/p/ufd/" target="_blank" rel="noopener"&#10; &gt;jquery.ui.ufd&lt;/a&gt;发现在jquery 1.7以上版本中文取值过滤有问题，总是显示前几项而非过滤项。查了半天才发现是jquery的滚轮事件originalEven的问题。StatckOverflow上的解释说在1.7以上的版本jquery event对象的detail属性不再可用而应使用event.originalEvent.detail来代替。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;listScroll&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bind&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;DOMMouseScroll mousewheel&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stopEvent&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;originalEvent&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//在&amp;gt;1.7版本的Jquery中得这样才能获取detail/wheelDelta&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;normal&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;detail&lt;/span&gt; &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;detail&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;wheelDelta&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;curST&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;listScroll&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;scrollTop&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newScroll&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;curST&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; ((&lt;span style="color:#a6e22e"&gt;normal&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#f92672"&gt;?&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;itemHeight&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;itemHeight&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;listScroll&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;scrollTop&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;newScroll&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/8886281/event-wheeldelta-returns-undefined" target="_blank" rel="noopener"&#10; &gt;event.wheelDelta returns undefined&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/14408348/binding-mousewheel-returns-undefined" target="_blank" rel="noopener"&#10; &gt;Binding mousewheel returns undefined&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP strtotime计算月份</title><link>https://courages.us/php-strtotime%E8%AE%A1%E7%AE%97%E6%9C%88%E4%BB%BD/</link><pubDate>Mon, 29 Jul 2013 22:15:52 +0800</pubDate><guid>https://courages.us/php-strtotime%E8%AE%A1%E7%AE%97%E6%9C%88%E4%BB%BD/</guid><description>&lt;p&gt;今天同事发现了一个php的月份bug，说月份列表里怎么出现了两个3月份，代码是大概是这样的：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;today&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-1 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-2 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-3 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-4 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;-5 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用strtotime来计算最近了六个月份，这个bug之前没有被发现因为只有在每月的29，30，31号才会发作：因为php默认取当前时间来做计算，比如今天7月29号减去5个月应该是2月29号，因为今年的2月份没有29号，所以就到了3月份了。&lt;/p&gt;&#10;&lt;p&gt;于是修改了下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;today&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;first day of -1 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;first day of -2 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;first day of -3 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;first day of -4 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;first day of -5 month&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是这个只有在php 5.3以上的版本中才会起作用，在php 5.2的版本有bug，需要这样处理：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;strtotime&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;today&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;mktime&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;)));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;mktime&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;)));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;mktime&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;)));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;mktime&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;)));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$month[]&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y年m月&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;mktime&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;)));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.php.net/manual/zh/function.strtotime.php#107331" target="_blank" rel="noopener"&#10; &gt;php strtotime函数&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/10250208/version-difference-for-strtotimefirst-day-of-last-month" target="_blank" rel="noopener"&#10; &gt;Version difference for strtotime(‘first day of last month’)?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Jquery ContextMenu插件改造</title><link>https://courages.us/jquery-contextmenu%E6%8F%92%E4%BB%B6%E6%94%B9%E9%80%A0/</link><pubDate>Sun, 28 Jul 2013 22:19:10 +0800</pubDate><guid>https://courages.us/jquery-contextmenu%E6%8F%92%E4%BB%B6%E6%94%B9%E9%80%A0/</guid><description>&lt;p&gt;最近需要在页面的表格上使用的右键弹出菜单，考察了下网络上的几个右键菜单发现都不太符合：需要能够用列表来布局菜单，而不是都放在javascript中控制。Jqueryui 的menu插件采用ul和li来布局，但是菜单项仅仅是个超级链接，不能结合当前被右键单击的元素进行动态传递参数和禁用/启用菜单。于是网上找了个&lt;a class="link" href="http://www.dynamicdrive.com/dynamicindex1/contextmenu.htm" target="_blank" rel="noopener"&#10; &gt;插件&lt;/a&gt;自己来改造。&lt;/p&gt;&#10;&lt;p&gt;首先增加了几个参数：currentTarget用于保存当前的右键单击事件的对象；actions用于根据菜单id来进行函数绑定；selector用于保存当前应用右键菜单的选择器；options对象用于保存一些其他的扩展参数，比如hover为鼠标滑过菜单的css样式，highlight为当前右键单击元素的css样式。actions对象可以包括多个子对象，每一个子对象可以包含两个函数click和disabled，前者响应用户单击菜单事件，后者则指示是否在当前右键对象上禁用相关菜单。两个函数都将传入两个参数：source和li，source为右键单击的(jquery)对象，li则是当前单击的菜单(jquery)对象。&lt;/p&gt;&#10;&lt;p&gt;用法示例:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;DOCTYPE&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;html&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PUBLIC&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;html&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;jqcontextmenu.css&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;jquery.min.js&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;jqcontextmenu.js&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;.&lt;span style="color:#a6e22e"&gt;myhighlight&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;background&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;DEDEDE&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;.&lt;span style="color:#a6e22e"&gt;myjqhover&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;background&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;DEDEDE&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/style&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//Usage: $(elementselector).addcontextmenu(&amp;#39;selector&amp;#39;,actions,options)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#a6e22e"&gt;jQuery&lt;/span&gt;(document).&lt;span style="color:#a6e22e"&gt;ready&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;p&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;addcontextmenu&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;contextmenu1&amp;#39;&lt;/span&gt;,{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;item1&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{&lt;span style="color:#75715e"&gt;//对应菜单的ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;){&lt;span style="color:#75715e"&gt;//需要进行单击菜单响应的&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//alert(source);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;item2&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;disabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;){&lt;span style="color:#75715e"&gt;//需要进行启用/禁用控制的&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;dp&amp;#39;&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//禁用&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//启用&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;item31&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#e6db74"&gt;&amp;#39;item521&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;click&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;alert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//alert(li.attr(&amp;#39;id&amp;#39;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;},{&lt;span style="color:#a6e22e"&gt;highlight&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;myhighlight&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;hover&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;myjqhover&amp;#39;&lt;/span&gt;}); &lt;span style="color:#75715e"&gt;//apply context menu to links with class=&amp;#34;mylinks&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;});&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/script&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/head&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dp&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mylinks&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#1&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dynamic&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Dynamic&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Drive&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;p&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dp2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mylinks&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#2&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dynamic2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Dynamic&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Drive2&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;div&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;float:right&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dadfasd&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;&amp;lt;!--&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HTML&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Menu&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;--&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ul&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;contextmenu1&amp;#34;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;jqcontextmenu&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;sep&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item3&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Folder&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ul&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item31&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3.1&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item3.2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3.2&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item3.3&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3.3&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item3.4&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3.4&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/ul&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item4&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item5&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Folder&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ul&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item5.1&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.1&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item5.2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Folder&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.2&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ul&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item521&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item5.2.2&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item5.2.3&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item5.2.4&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Sub&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.2&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/ul&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/ul&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;item6&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/ul&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/body&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/html&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个插件是在jquery 1.7以上版本进行修改和测试，jqcontextmenu项目&lt;a class="link" href="http://git.oschina.net/huangcanqiang/jqcontextmenu" target="_blank" rel="noopener"&#10; &gt;osc地址&lt;/a&gt;。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.dynamicdrive.com/dynamicindex1/contextmenu.htm" target="_blank" rel="noopener"&#10; &gt;jQuery Context Menu script&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.developersnippets.com/2011/09/02/bunch-of-widely-used-jquery-context-menus/" target="_blank" rel="noopener"&#10; &gt;Bunch Of Widely Used jQuery Context Menus&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/arnklint/jquery-contextMenu" target="_blank" rel="noopener"&#10; &gt;arnklint/jquery-contextMenu&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://github.com/medialize/jQuery-contextMenu" target="_blank" rel="noopener"&#10; &gt;medialize/jQuery-contextMenu&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.web-delicious.com/jquery-plugins-demo/wdContextMenu/sample.htm?1319251008" target="_blank" rel="noopener"&#10; &gt;wdContextMenu Samples vs Code&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://i.80tvb.com/jquery-contextmenu/" target="_blank" rel="noopener"&#10; &gt;jQuery右键菜单插件ContextMenu使用笔记&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="jQuery%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95%e6%8f%92%e4%bb%b6ContextMenu" &gt;jQuery右键菜单插件ContextMenu&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Javascript 中解析XML</title><link>https://courages.us/javascript-%E4%B8%AD%E8%A7%A3%E6%9E%90xml/</link><pubDate>Tue, 04 Jun 2013 22:50:43 +0800</pubDate><guid>https://courages.us/javascript-%E4%B8%AD%E8%A7%A3%E6%9E%90xml/</guid><description>&lt;p&gt;通常在Javascript中做数据交换用的都是json也比较方便，但是这次碰到xml字符串解析。查了下，发现不同浏览器还不一样，解析起来倒也不难。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;&amp;lt;note&amp;gt;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;to id=&amp;#34;to&amp;#34;&amp;gt;Tove&amp;lt;/to&amp;gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;from&amp;gt;Jani&amp;lt;/from&amp;gt;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;heading&amp;gt;Reminder&amp;lt;/heading&amp;gt;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;body&amp;gt;Don\&amp;#39;t forget me this weekend!&amp;lt;/body&amp;gt;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;/note&amp;gt;&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (window.&lt;span style="color:#a6e22e"&gt;DOMParser&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;parser&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DOMParser&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;xmlDoc&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;parser&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;parseFromString&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;text/xml&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#75715e"&gt;// Internet Explorer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;xmlDoc&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ActiveXObject&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft.XMLDOM&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;xmlDoc&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;xmlDoc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;loadXML&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;txt&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//获取to的文本值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_text&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;xmlDoc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getElementsByTagName&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;to&amp;#39;&lt;/span&gt;)[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;childNodes&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;nodeValue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//获取to的属性值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;xmlDoc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getElementsByTagName&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;to&amp;#39;&lt;/span&gt;)[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].&lt;span style="color:#a6e22e"&gt;getAttribute&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果有用到Jquery的话也可以使用$.parseXML()，然后就可以使用Jquery的选择器和方法了&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;note&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;parseXML&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//找到to节点&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;note&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;find&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;to&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//获取to的文本值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_text&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;text&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//获取to的属性值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;to&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//如果to有多个的话,可以先判断to.length&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//然后又下标去访问或者用$.fn.each()遍历访问&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//var to_text=$(to[0]).text();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果是通过Ajax请求的返回回来的数据，可以$.ajax中设置请求参数dataType:’xml’，然后就可以使用Jquery的选择器。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.w3schools.com/dom/dom_nodes_get.asp" target="_blank" rel="noopener"&#10; &gt;XML DOM Get Node Values&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.nowamagic.net/jquery/jquery_ParsingXmlData.php" target="_blank" rel="noopener"&#10; &gt;JQuery解析XML数据的几个例子&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://api.jquery.com/jQuery.parseXML/" target="_blank" rel="noopener"&#10; &gt;jQuery.parseXML&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP base64_decode 空格问题</title><link>https://courages.us/php-base64_decode-%E7%A9%BA%E6%A0%BC%E9%97%AE%E9%A2%98/</link><pubDate>Sun, 02 Jun 2013 17:42:34 +0800</pubDate><guid>https://courages.us/php-base64_decode-%E7%A9%BA%E6%A0%BC%E9%97%AE%E9%A2%98/</guid><description>&lt;p&gt;php对一个base64_encode编码后的字符串通过url传递后进行base64_decode发现返回值是false。尝试将url传递后的值打印出来发现+都被换成了空格。上网查了下发现，对于通过application/x-www-form-urlencoded的HTTP传递值，+会被自动替换为空格。所以也有各种对base64编码进行扩充的，比如对+,/等符号进行替换的，以便HTTP传输。在php中需要将+号或空格做退还，比如简单的str_replace(‘ ‘,’+’,$str)或者在传输前做urlencode。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/5628738/strange-base64-encode-decode-problem" target="_blank" rel="noopener"&#10; &gt;Strange Base64 encode/decode problem&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zh.wikipedia.org/wiki/Base64" target="_blank" rel="noopener"&#10; &gt;Base64&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Jquery下清空表单FILE控件的值</title><link>https://courages.us/jquery%E4%B8%8B%E6%B8%85%E7%A9%BA%E8%A1%A8%E5%8D%95file%E6%8E%A7%E4%BB%B6%E7%9A%84%E5%80%BC/</link><pubDate>Sun, 02 Jun 2013 17:11:47 +0800</pubDate><guid>https://courages.us/jquery%E4%B8%8B%E6%B8%85%E7%A9%BA%E8%A1%A8%E5%8D%95file%E6%8E%A7%E4%BB%B6%E7%9A%84%E5%80%BC/</guid><description>&lt;p&gt;有时编辑表单需要清除表单的值，使用Jquery的话就是$(this).val(”)或者$(this).attr(‘value’,”)就可以清空了，但是在ie 8下却不行。在网上找了下说是出于安全性的原因，不能在javascript中对FILE控件操作。解决方法是ie下用在身的克隆来替换掉，代码如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;browser&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;msie&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#file&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;replaceWith&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#file&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;clone&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;$&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#file&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;val&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ie下的安全性有时候很讨厌，比如说自定义FILE控件样式，非得点击在控件上选择文件才行，而不能使用javascript来代替。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/13745384/resetting-input-file-using-this-val-not-working-with-ie8" target="_blank" rel="noopener"&#10; &gt;resetting input file using $(this).val(“”) not working with IE8&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://forum.jquery.com/topic/how-to-clear-a-file-input-in-ie" target="_blank" rel="noopener"&#10; &gt;How to clear a FILE input in IE?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP安全问题</title><link>https://courages.us/php%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/</link><pubDate>Fri, 29 Mar 2013 16:42:59 +0800</pubDate><guid>https://courages.us/php%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/</guid><description>&lt;p&gt;在&lt;a class="link" href="http://wooyun.org/index.php" target="_blank" rel="noopener"&#10; &gt;乌云漏洞平台&lt;/a&gt;上发现很多开源PHP程序存在漏洞。大部分漏洞都是因为对PHP中的变量过滤不够严格和未转义造成，直接使用了$_GET，$_PUT，$_COOKIE传过来的值，造成了sql注入（sql injection）和跨站攻击（xss）。事实上这些漏洞完全可以避免的。&lt;br&gt;&#10;先说sql注入。通常注入情况发生在参数过滤不严谨和拼接sql，所以尽量不要用sql拼接，尽量使用PDO或Mysqli。&lt;/p&gt;&#10;&lt;p&gt;先看下面一段代码（test.php）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$database&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$duser&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$dpassword&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;*********&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$server&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$link&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mysql_connect&lt;/span&gt;($server,$duser,$dpassword) &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;连接不上服务器：&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mysql_error&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mysql_select_db&lt;/span&gt;($database,$link) &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;die&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;不能选择数据库&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$_GET[&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sql&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;select id,account,nickname,password from user where id=&amp;#39;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$id&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $sql;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$res&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mysql_query&lt;/span&gt;($sql);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$arr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mysql_fetch_array&lt;/span&gt;($res,&lt;span style="color:#a6e22e"&gt;MYSQL_ASSOC&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后访问http://127.0.0.1/test.php?id=1，获取用户信息。这是可以通过构造参数进行攻击比如&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//访问：http://127.0.0.1/test.php?id=1%27%20OR%201%20=%201--%27&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//将可以查询出所有的表数据。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sql&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;select id,account,nickname,password from user where id=&amp;#39;1&amp;#39; OR 1 = 1--&amp;#39;&amp;#39;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//访问：http://127.0.0.1/test.php?id=1%27%20UNION%20ALL%20%28SELECT%20NULL,NULL,NULL,%27%3C?php%20system%28$_GET[%22command%22]%29;%20?%3E%27%20INTO%20OUTFILE%20%27D:/www/shell.php%27%29%20--%20-%27&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//在知道网站路径情况下，在网站目录下生成shell.php，将能够在对用户的网站进行挂马，提权的操作。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sql&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;select id,account,nickname,password from user where id=&amp;#39;1&amp;#39; UNION ALL (SELECT NULL,NULL,NULL,&amp;#39;&amp;#39; INTO OUTFILE &amp;#39;D:/www/shell.php&amp;#39;) -- -&amp;#39;&amp;#39;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;甚至还可以进行表数据的增加，修改，删除，数据库的删除！所以永远不要相信用户的输入，永远要过滤输入，转义输出。对传递过来的数字型变量要进行严格的匹配，对字符串型的变量进行长度限制。注意过滤用户传递过来的变量是否包含引号，/*，#，—等特殊字符或转义字符，script，drop，不要给用户超级权限，最好进行分隔。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//使用addslashes过滤单引号，双引号和斜杠&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$uname &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;addslashes&lt;/span&gt;( $_GET[&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;] );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;SELECT username FROM users WHERE id = &amp;#34;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $uname &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//使用mysql_real_escape_string过滤特殊字符，比如\x00, \n, \r, \, &amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;,&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\x1a&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//mysql_real_escape_string使用的是本地单字节字符集，而我们传递多字节编码的变量时，有可能还是会造成SQL注入漏洞&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//如chr(0xbf) . chr(0x27)，所以mysql服务端与php客户端通信尽量使用utf-8而不是gbk&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$uname&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = mysql_real_escape_string( &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$_GET[&amp;#39;id&amp;#39;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$query&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = &amp;#39;SELECT username FROM users WHERE id = &amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; . $uname . &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//使用is_numeric检查数字型变量&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$_GET[&amp;#39;id&amp;#39;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;( is_numeric( &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt; ) ? TRUE : FALSE );&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//使用sprintf格式化数字型变量&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$_GET[&amp;#39;id&amp;#39;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$query&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = sprintf(&amp;#34;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SELECT&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;username&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;FROM&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;users&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WHERE&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%d&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;, &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//使用htmlentities(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$var&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, ENT_QUOTES)转义所有的html标记&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$_GET[&amp;#39;id&amp;#39;]&lt;/span&gt;&lt;span style="color:#e6db74"&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = htmlentities( &lt;/span&gt;&lt;span style="color:#e6db74"&gt;$id&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, ENT_QUOTES, &amp;#39;UTF-8&amp;#39; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$query&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = &amp;#39;SELECT username FROM users WHERE id = &amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; . $id . &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#39;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//使用filter_var过滤script标签，防止xss&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;//&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$str&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = strip_tags(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$input&lt;/span&gt;&lt;span style="color:#e6db74"&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$str&lt;/span&gt;&lt;span style="color:#e6db74"&gt; = filter_var(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;$input&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, FILTER_SANITIZE_STRING);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果PHP支持PDO可以的话，就不要拼接sql，尽量使用PDO或Mysqli。使用PDO要在PDO的DSN中指定charset属性，要设置PDO::ATTR_EMULATE_PREPARES参数为false，禁止php进行本地转义，造成双字节转义攻击，如果没有必要，msyql服务端与php客户端应该都是用utf-8进行通信，而不是gbk。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pdo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PDO&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mysql:host=192.168.0.1;dbname=test;&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pdo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setAttribute&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;PDO&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ATTR_EMULATE_PREPARES&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$st &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $pdo&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;prepare&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;select * from info where id =? and name = ?&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zhangsan&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$st&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bindParam&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,$id);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$st&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bindParam&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,$name);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$st&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;execute&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$st&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fetchAll&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除了过滤，变量务必初始化，不要自动获得变量，用户将可以构造任何变量进行攻击。&lt;br&gt;&#10;不要这样随意，将造成文件包含攻击&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($_GET[&lt;span style="color:#e6db74"&gt;&amp;#39;page&amp;#39;&lt;/span&gt;]) {&lt;span style="color:#75715e"&gt;//if(file_exists($_GET[&amp;#39;page&amp;#39;])) {非严格的检测 http://localhost/index.php?page=/etc/passwd%00&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;include&lt;/span&gt;($_GET[&lt;span style="color:#e6db74"&gt;&amp;#39;page&amp;#39;&lt;/span&gt;]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;?&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要进行严格的匹配，或者做映射&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($_GET[&lt;span style="color:#e6db74"&gt;&amp;#39;page&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;news&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;include&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;news.php&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;?&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关闭浏览器输出的错误报告，避免泄漏文件目录路径，错误报告应输出到日记文件中&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#php.ini&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;display_errors = &amp;#39;off&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#apache2.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;php_flag display_errors off&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;php当中&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ini_set&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;display_errors&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;页面的访问要设置权限，特别是执行查询的或者录入的页面，简单设置如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;APP_ADMIN&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;defined&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;APP_ADMIN&amp;#39;&lt;/span&gt;)) &lt;span style="color:#66d9ef"&gt;exit&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应该做一个更为完善的权限系统，如基于角色的权限管理系统，最好细致到页面（元素）。&lt;br&gt;&#10;eval函数针对php安全有很大杀伤力，为了防止挂马，应禁用eval函数。&lt;br&gt;&#10;下载的页面必须设置下载目录，对要下载的文件进行检测或做目录权限控制，生成临时下载链接，不允许下载任意的文件。对于系统配置文件，日记文件等要做分离，建议像zend framework那样设置web目录，程序与web目录分开，避免泄漏源码等。不要将.svn文件直接放置在web目录，会导致源码泄露。&lt;br&gt;&#10;上传的页面必须进行类型检测，不要只截取扩展名，设置权限，不允许可执行文件。这里是网友写的一个文件类型检查类&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/*通过文件名，获得文件类型*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *@author chengmo QQ:8292669*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *@copyright &amp;lt;a href=&amp;#34;http://www.cnblogs.com/chengmo&amp;#34;&amp;gt;http://www.cnblogs.com/chengmo&amp;lt;/a&amp;gt; 2010-10-17&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *@version 0.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; *$filename=&amp;#34;d:/1.png&amp;#34;;echo cFileTypeCheck::getFileType($filename); 打印：png&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cFileTypeCheck&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; $_TypeList&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; $CheckClass&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($filename)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;$_TypeList&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getTypeList&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *处理文件类型映射关系表*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param string $filename 文件类型&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return string 文件类型，没有找到返回：other&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_getFileType&lt;/span&gt;($filename)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $filetype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;other&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;file_exists&lt;/span&gt;($filename)) &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;no found file!&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;($filename,&lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$file) &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;file refuse!&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $bin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fread&lt;/span&gt;($file, &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;); &lt;span style="color:#75715e"&gt;//只读15字节 各个不同文件类型，头信息不一样。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($file);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $typelist&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;$_TypeList;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; ($typelist &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $v)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $blen&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;pack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;H*&amp;#34;&lt;/span&gt;,$v[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;])); &lt;span style="color:#75715e"&gt;//得到文件头标记字节数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $tbin&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;substr&lt;/span&gt;($bin,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;intval&lt;/span&gt;($blen)); &lt;span style="color:#75715e"&gt;///需要比较文件头长度&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;strtolower&lt;/span&gt;($v[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;])&lt;span style="color:#f92672"&gt;==&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;strtolower&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;array_shift&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;unpack&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;H*&amp;#34;&lt;/span&gt;,$tbin)))) &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $v[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $filetype;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *得到文件头与文件类型映射表*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; *&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return array array(array(&amp;#39;key&amp;#39;,value)...)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getTypeList&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;FFD8FFE1&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;jpg&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;89504E47&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;png&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;47494638&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;gif&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;49492A00&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;tif&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;424D&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;bmp&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;41433130&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dwg&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;38425053&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;psd&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;7B5C727466&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;rtf&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;3C3F786D6C&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;xml&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;68746D6C3E&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;html&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;44656C69766572792D646174&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;eml&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;CFAD12FEC5FD746F&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;dbx&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;2142444E&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;pst&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;D0CF11E0&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;xls/doc&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;5374616E64617264204A&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;mdb&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;FF575043&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;wpd&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;252150532D41646F6265&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;eps/ps&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;255044462D312E&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;pdf&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;E3828596&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;pwl&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;504B0304&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;zip&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;52617221&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;rar&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;57415645&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;wav&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;41564920&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;avi&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;2E7261FD&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;ram&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;2E524D46&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;rm&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;000001BA&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;mpg&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;000001B3&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;mpg&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;6D6F6F76&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;mov&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;3026B2758E66CF11&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;asf&amp;#34;&lt;/span&gt;),&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;4D546864&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;mid&amp;#34;&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getFileType&lt;/span&gt;($filename)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;$CheckClass) &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;$CheckClass&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;($filename);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $class&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;$CheckClass;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $class&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_getFileType&lt;/span&gt;($filename);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;22.jpg&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $filename,&lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;cFileTypeCheck&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getFileType&lt;/span&gt;($filename),&lt;span style="color:#e6db74"&gt;&amp;#34;rn&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$filename&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;11.doc&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $filename,&lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;cFileTypeCheck&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getFileType&lt;/span&gt;($filename),&lt;span style="color:#e6db74"&gt;&amp;#34;rn&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于暴力破解设置验证码，或者限制ip次数。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.unixwiz.net/techtips/sql-injection.html" target="_blank" rel="noopener"&#10; &gt;SQL Injection Attacks by Example&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://hakipedia.com/index.php/SQL_Injection" target="_blank" rel="noopener"&#10; &gt;SQL Injection&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.websec.ca/kb/sql_injection" target="_blank" rel="noopener"&#10; &gt;Injection&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/en/security.database.sql-injection.php" target="_blank" rel="noopener"&#10; &gt;PHP SQL Injection&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://hi.baidu.com/thinkinginlamp/item/8fe5a5bb41f4c3422aebe3fb" target="_blank" rel="noopener"&#10; &gt;PHP+MySQL环境下SQL Injection攻防总结&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://zhangxugg-163-com.iteye.com/blog/1835721" target="_blank" rel="noopener"&#10; &gt;PDO防注入原理分析以及使用PDO的注意事项&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string" target="_blank" rel="noopener"&#10; &gt;SQL injection that gets around mysql_real_escape_string()&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.i0day.com/788.html" target="_blank" rel="noopener"&#10; &gt;MySQL远程提权php版&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet" target="_blank" rel="noopener"&#10; &gt;XSS Filter Evasion Cheat Sheet&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/chengmo/archive/2010/10/17/1853710.html" target="_blank" rel="noopener"&#10; &gt;php通过文件头检测文件类型通用类（zip,rar…)&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/chengmo/archive/2010/12/06/1898062.html" target="_blank" rel="noopener"&#10; &gt;php 验证码【倾斜，正弦干扰线，黏贴，旋转&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP 自动加载类</title><link>https://courages.us/php-%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E7%B1%BB/</link><pubDate>Wed, 20 Mar 2013 23:52:27 +0800</pubDate><guid>https://courages.us/php-%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E7%B1%BB/</guid><description>&lt;p&gt;老的项目很多不规范，到处都是require/include_once。为了不再到处写require/include(_once)了，应该给项目写个自动加载器了，避免重复加载和建立规范。个人觉得require_once和require之间的性能差异不大，特别是开启了APC缓存后,手动加载和自动加载之间的差异也不大。关于APC缓存类文件有争议，建议阅读参考链接和相关评论。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;autoloader&lt;/span&gt;($class){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;class_exists&lt;/span&gt;($class, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;interface_exists&lt;/span&gt;($class, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)) {&lt;span style="color:#75715e"&gt;//如果已存在就不需要了&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;$directorys &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;MVC_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;library&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;MVC_PATH&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;str_replace&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, $class) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;.php&amp;#39;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//对类命名进行文件路径解析映射&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt;($directorys &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $directory){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;file_exists&lt;/span&gt;($directory&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$file)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&#9;&lt;span style="color:#66d9ef"&gt;require_once&lt;/span&gt;($directory&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$file);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spl_autoload_register&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;autoloader&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;zend framework官方的优化建议里建议去掉require_once改用Zend_Loader_Autoloader，认为require_once会花掉很多时间。官方有去除require_once的shell脚本，这里发一个windows下注释掉zend framework library 中的require_once的bat脚本，建议还是用其他工具比较好。这个脚本也可以用来批量查找替换指定目录下面，指定后缀（类型）文件中的指定字符串。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@echo off&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set directory=D:\PROGRA~1\wamp\www\&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set ext_name=php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set old_char=require_once&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set new_char=//require_once&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setlocal enabledelayedexpansion&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;for /r %directory% %%x in (*.%ext_name%) do ( &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; for /f &amp;#34;tokens=*&amp;#34; %%i in (%%x) do (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set &amp;#34;var=%%i&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set &amp;#34;var=!var:%old_char%=%new_char%!&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo !var!&amp;gt;&amp;gt;tmp.php&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;move tmp.php %%x&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.php.net/manual/en/language.oop5.autoload.php" target="_blank" rel="noopener"&#10; &gt;PHP Autoloading Classes&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.verydemo.com/demo_c116_i4919.html" target="_blank" rel="noopener"&#10; &gt;ZendFramework官方提供的优化没有实际意义&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2012/09/12/2765.html" target="_blank" rel="noopener"&#10; &gt;再一次, 不要使用(include/require)_once&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.ircmaxell.com/2012/07/is-autoloading-good-solution.html" target="_blank" rel="noopener"&#10; &gt;Is Autoloading A Good Solution?&lt;/a&gt;&lt;/p&gt;</description></item><item><title>在Yaf中应用Zend_Log</title><link>https://courages.us/%E5%9C%A8yaf%E4%B8%AD%E5%BA%94%E7%94%A8zend_log/</link><pubDate>Tue, 19 Mar 2013 16:43:07 +0800</pubDate><guid>https://courages.us/%E5%9C%A8yaf%E4%B8%AD%E5%BA%94%E7%94%A8zend_log/</guid><description>&lt;p&gt;Zend Framework是Zend 官方用PHP写的一套MVC框架，里面包含了诸多组件，可以单独使用，但是在PHP的MVC框架中的性能评测中总是处于下风。在之前的项目中有使用过Zend Framework，对于结构和代码的规范有比较好的帮助，类库也非常全面，所以想在其他的一些项目中也能够应用到Zend Framework的一些Library。&lt;a class="link" href="https://github.com/laruence/php-yaf" target="_blank" rel="noopener"&#10; &gt;Yaf&lt;/a&gt;是&lt;a class="link" href="http://www.laruence.com/" target="_blank" rel="noopener"&#10; &gt;国内牛人&lt;/a&gt;仿Zend Framework开发的一个PHP MVC框架的C扩展，性能较Zend Framework有巨大的提升，但是不如Zend Framework全面，更侧重于前端控制，大概后端用其方法来做更好。Yaf的文档少了些，而Zend Framework的应用则比较多，社区支持也更广泛。所以在新的项目采用了Yaf做为前端的分发管理器，结合Zend Framework的类库来进行开发。&lt;br&gt;&#10;本文是关于Zend_Log中添加Zend_Log_Writer_Firebug无效，不能输出到firebug的解决方法。其实这个问题刚好在其他项目中应用的时候也有碰到，之后在stackoverflow上找到了答案，原来是这个功能还依赖于Zend_Wildfire_Channel_HttpHeaders，又需要Zend_Controller_Request_Http和Zend_Controller_Response_Http。于是就仿着写了一个Yaf扩展，代码如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Ap定义了如下的7个Hook,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 插件之间的执行顺序是先进先Call&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WildfireChannelPlugin&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Yaf_Plugin_Abstract&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;routerStartup&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Request_Abstract&lt;/span&gt; $request, &lt;span style="color:#a6e22e"&gt;Yaf_Response_Abstract&lt;/span&gt; $response) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;routerShutdown&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Request_Abstract&lt;/span&gt; $request, &lt;span style="color:#a6e22e"&gt;Yaf_Response_Abstract&lt;/span&gt; $response) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dispatchLoopStartup&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Request_Abstract&lt;/span&gt; $request, &lt;span style="color:#a6e22e"&gt;Yaf_Response_Abstract&lt;/span&gt; $response) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_request&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zend_Controller_Request_Http&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_response&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zend_Controller_Response_Http&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zend_Wildfire_Channel_HttpHeaders&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getInstance&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setRequest&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_request&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setResponse&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_response&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;ob_start&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;preDispatch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Request_Abstract&lt;/span&gt; $request, &lt;span style="color:#a6e22e"&gt;Yaf_Response_Abstract&lt;/span&gt; $response) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;postDispatch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Request_Abstract&lt;/span&gt; $request, &lt;span style="color:#a6e22e"&gt;Yaf_Response_Abstract&lt;/span&gt; $response) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dispatchLoopShutdown&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Request_Abstract&lt;/span&gt; $request, &lt;span style="color:#a6e22e"&gt;Yaf_Response_Abstract&lt;/span&gt; $response) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;isset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;flush&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_response&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sendHeaders&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在Bootstrap.php中注册扩展，代码如下:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_initPlugin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Dispatcher&lt;/span&gt; $dispatcher) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Yaf_Registry&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;config&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;log&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;firebug&amp;#34;&lt;/span&gt;)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$WildfireChannel &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WildfireChannelPlugin&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$dispatcher&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;registerPlugin&lt;/span&gt;($WildfireChannel);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后，Zend_Log_Writer_Firebug和firebug就可以正常工作了。如果要在其他项目中应用，只需要在开始输出前和输出结束后，分别调用上面连个方法就可以了，比如在启动文件中：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Boot&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $_request;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $_response;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $_channel;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_initWildfireChannel&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_request&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zend_Controller_Request_Http&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_response&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zend_Controller_Response_Http&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Zend_Wildfire_Channel_HttpHeaders&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getInstance&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setRequest&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_request&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setResponse&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_response&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#a6e22e"&gt;ob_start&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;isset&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_channel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;flush&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_response&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sendHeaders&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后按需打开WildfireChannel就可以了。&lt;br&gt;&#10;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/5322208/zend-log-writer-firebug-not-working" target="_blank" rel="noopener"&#10; &gt;Zend_Log_Writer_Firebug() not working&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.oschina.net/p/phalcon" target="_blank" rel="noopener"&#10; &gt;高性能PHP框架 Phalcon&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://framework.zend.com/" target="_blank" rel="noopener"&#10; &gt;Zend Framework&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP脚本建立中国县市数据库</title><link>https://courages.us/php%E8%84%9A%E6%9C%AC%E5%BB%BA%E7%AB%8B%E4%B8%AD%E5%9B%BD%E5%8E%BF%E5%B8%82%E6%95%B0%E6%8D%AE%E5%BA%93/</link><pubDate>Mon, 18 Mar 2013 21:51:39 +0800</pubDate><guid>https://courages.us/php%E8%84%9A%E6%9C%AC%E5%BB%BA%E7%AB%8B%E4%B8%AD%E5%9B%BD%E5%8E%BF%E5%B8%82%E6%95%B0%E6%8D%AE%E5%BA%93/</guid><description>&lt;p&gt;在做快递查询的时候需要一个中国的县市数据库，由于之前的人做行政区域是用了一个Javascript脚本做的不好在后台动态交互，在网上看到了一篇关于建立中国行政区域数据库的文章，非常好，mark一下，以免以后找不到。首先需要到&lt;a class="link" href="http://www.stats.gov.cn/tjbz/xzqhdm/index.htm" target="_blank" rel="noopener"&#10; &gt;国家统计局&lt;/a&gt;下载最新的文档（打开最新的页面，全部复制下来另存为region.txt）。然后建一个数据库表region&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;region&lt;span style="color:#f92672"&gt;`&lt;/span&gt; (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;`&lt;/span&gt;id&lt;span style="color:#f92672"&gt;`&lt;/span&gt; int(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) unsigned &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;`&lt;/span&gt;parent_id&lt;span style="color:#f92672"&gt;`&lt;/span&gt; int(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) unsigned &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;`&lt;/span&gt;name&lt;span style="color:#f92672"&gt;`&lt;/span&gt; varchar(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt; (&lt;span style="color:#f92672"&gt;`&lt;/span&gt;id&lt;span style="color:#f92672"&gt;`&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)ENGINE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;MYISAM &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; CHARSET&lt;span style="color:#f92672"&gt;=&lt;/span&gt;utf8;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在相同目录下建立一个文件region.php，代码如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;set_time_limit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;ENGLISH_BLANK&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;chr&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;define&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;CHINESE_BLANK&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;chr&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;227&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chr&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;) &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chr&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;128&lt;/span&gt;));&lt;span style="color:#75715e"&gt;// ã€€&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mysql_connect&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;root&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;********&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mysql_select_db&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mysql_query&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;SET NAMES &amp;#39;utf8&amp;#39;&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$parent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$handle &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;region.txt&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;feof&lt;/span&gt;($handle)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//每次取一行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//由于该文本时采用空格缩进来确定上下级关系的，&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//用自定义的空格字符串代替两个英文空格，&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//利用自定义的空格切分字符串，这样在转换为数组时可以确定层级&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;explode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;CHINESE_BLANK&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;str_replace&lt;/span&gt;(&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ENGLISH_BLANK&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ENGLISH_BLANK&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;CHINESE_BLANK&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;trim&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;fgets&lt;/span&gt;($handle))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;is_numeric&lt;/span&gt;($id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_shift&lt;/span&gt;($data))) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $level &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//如果只有两个英文空格的话，那么便是顶级了，否则级数++&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (($value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;array_shift&lt;/span&gt;($data)) &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($value &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $level&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $parent[$level] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $parent_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $level &lt;span style="color:#f92672"&gt;?&lt;/span&gt; $parent[$level &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//构建了一个数组比如$parent[0]=110000 ;$parent[1]=110100;$parent[2]=$id;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//这样子便可以根据它所缩进的空格数，确定它的层级，根据层级取得父id&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $value;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;($data)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $name &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;implode&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;, $data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $sql &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; INSERT INTO region (id, parent_id, name)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; VALUES (&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$id&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$parent_id&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;$name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mysql_query&lt;/span&gt;($sql);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($handle);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在命令行运行php region.php，我的结果行数是3511。&lt;br&gt;&#10;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://hi.baidu.com/thinkinginlamp/item/91d15980e1ba8bcdef083dcb" target="_blank" rel="noopener"&#10; &gt;实用PHP脚本：最新县及县以上行政区划代码&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP 使用ZipArchive压缩文件并下载</title><link>https://courages.us/php-%E4%BD%BF%E7%94%A8ziparchive%E5%8E%8B%E7%BC%A9%E6%96%87%E4%BB%B6%E5%B9%B6%E4%B8%8B%E8%BD%BD/</link><pubDate>Mon, 18 Mar 2013 11:17:01 +0800</pubDate><guid>https://courages.us/php-%E4%BD%BF%E7%94%A8ziparchive%E5%8E%8B%E7%BC%A9%E6%96%87%E4%BB%B6%E5%B9%B6%E4%B8%8B%E8%BD%BD/</guid><description>&lt;p&gt;网站上需要提供一些打印数据给用户下载，这些文件每次都需要重新生成，因为随时都会有新的数据产生。网络上关于PHP的压缩功能实现有多种方式，比如PclZip,ZipArchive等。PclZip是使用PHP写的一个压缩解压类，方便使用，不用安装扩展；而ZipArchive则在PHP 5.3之后随PHP携带发行，不需要再去开启扩展。本文则使用PHP自带的ZipArchive进行文档压缩。&lt;br&gt;&#10;由于还要提供给用户下载，这里参考了网络上下载类，以下为downlaod.class.php代码&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;download&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $_filename;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $_filepath;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; &lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; $_filesize;&lt;span style="color:#75715e"&gt;//文件大小&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($filename){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filename&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$filename;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dirname&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$filename;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;() {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;file_exists&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;unlink&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//获取文件名&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getfilename&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filename&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//获取文件路径（包含文件名）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getfilepath&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//获取文件大小&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getfilesize&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filesize&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;number_format&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;filesize&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;),&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//去小数点后两位&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#75715e"&gt;//下载文件的功能&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getfiles&lt;/span&gt;(){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#75715e"&gt;//检查文件是否存在&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;file_exists&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//打开文件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;r&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//返回的文件类型&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Content-type: application/octet-stream&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//按照字节大小返回&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Accept-Ranges: bytes&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//返回文件的大小&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Accept-Length: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;filesize&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//这里对客户端的弹出对话框，对应的文件名&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;Header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Content-Disposition: attachment; filename=&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filename&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//修改之前，一次性将数据传输给客户端&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fread&lt;/span&gt;($file, &lt;span style="color:#a6e22e"&gt;filesize&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_filepath&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//修改之后，一次只传输1024个字节的数据给客户端&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//向客户端回送数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;$buffer&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//判断文件是否读完&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;feof&lt;/span&gt;($file)) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//将文件读入内存&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;$file_data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fread&lt;/span&gt;($file,$buffer);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//每次向客户端回送1024个字节的数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $file_data;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($file);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;script&amp;gt;alert(&amp;#39;对不起,您要下载的文件不存在&amp;#39;);&amp;lt;/script&amp;gt;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ZipArchive有两个添加文件的方法addFile 和addFromString，addFile可将现有文件添加进去，而addFromStrin则可以添加一些动态的文本 。在要下载文件中则简单调用，代码如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;include&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;download.class.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$res&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//动态结果&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$zip&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZipArchive&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$zipname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;YmdHis&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;())&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;.zip&amp;#39;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//随机文件名&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;file_exists&lt;/span&gt;($zipname)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $zip&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;($zipname,&lt;span style="color:#a6e22e"&gt;ZipArchive&lt;/span&gt;&lt;span style="color:#f92672"&gt;::&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;OVERWRITE&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//创建一个空的zip文件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$zip-&amp;gt;addFile(&amp;#39;/images/show.pic&amp;#39;,&amp;#39;show.pic&amp;#39;);//将/images/show.pic文件添加进去&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$content=file_get_contents(&amp;#39;http://127.0.0.1/data.php?r=&amp;#39;$res);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//if ( $content !== false ) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$zip-&amp;gt;addFromString(&amp;#39;data.xml&amp;#39;,$content);//使用字符串的方式动态添加&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $zip&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addFromString&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;test.txt&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;some text ...&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $zip&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;close&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dw&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;download&lt;/span&gt;($zipname); &lt;span style="color:#75715e"&gt;//下载文件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $dw&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getfiles&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;unlink&lt;/span&gt;($zipname); &lt;span style="color:#75715e"&gt;//下载完成后要主动删除 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意在windows平台下压缩的文件路径在linux可能识别不了。&lt;br&gt;&#10;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.ccvita.com/330.html" target="_blank" rel="noopener"&#10; &gt;PclZip:强大的PHP压缩与解压缩zip类&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.yuansir-web.com/2011/08/31/php-ziparchive-%E5%AE%9E%E7%8E%B0%E5%8E%8B%E7%BC%A9%E8%A7%A3%E5%8E%8Bzip%E6%96%87%E4%BB%B6/" target="_blank" rel="noopener"&#10; &gt;PHP ZipArchive 实现压缩解压Zip文件&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/hongfei/archive/2012/06/12/2546881.html" target="_blank" rel="noopener"&#10; &gt;文件打包，下载之使用PHP自带的ZipArchive压缩文件并下载打包好的文件&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.php.net/manual/zh/class.ziparchive.php" target="_blank" rel="noopener"&#10; &gt;php ZipArchive class&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP SimpleXMLElement的陷阱</title><link>https://courages.us/php-simplexmlelement%E7%9A%84%E9%99%B7%E9%98%B1/</link><pubDate>Wed, 27 Feb 2013 18:29:04 +0800</pubDate><guid>https://courages.us/php-simplexmlelement%E7%9A%84%E9%99%B7%E9%98%B1/</guid><description>&lt;p&gt;PHP 使用SimpleXMLElement的addChild方法添加另一个SimpleXMLElement对象的时候老是取不到完整的对象。原本参考了网上的&lt;a class="link" href="http://www.php.net/manual/en/simplexmlelement.addchild.php#105158" target="_blank" rel="noopener"&#10; &gt;例子&lt;/a&gt;以为可以直接添加，示例代码如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$orders&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleXMLElement&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&amp;lt;orders&amp;gt;&amp;lt;/orders&amp;gt; &amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $order&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleXMLElement&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&amp;lt;order&amp;gt;&amp;lt;/order&amp;gt; &amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$order&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;item&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;,$i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;shoes&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;price&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;110.00&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//echo $order-&amp;gt;asXML();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $orders&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;($order&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;(),$order);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//$orders-&amp;gt;{$order-&amp;gt;getName()}[]=$order;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $orders&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;asXML&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现$orders中的order子元素总是为空，不会包含item项等，但是在循环中调试打印出$order却又是完整。后来找到了&lt;a class="link" href="http://stackoverflow.com/questions/4778865/php-simplexml-addchild-with-another-simplexmlelement" target="_blank" rel="noopener"&#10; &gt;这个&lt;/a&gt;，据说是因为SimpleXMLElement没有对要添加的对象做深复制，解决方法之一便是借助DOM。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sxml_append&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;SimpleXMLElement&lt;/span&gt; $to, &lt;span style="color:#a6e22e"&gt;SimpleXMLElement&lt;/span&gt; $from) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $toDom &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dom_import_simplexml&lt;/span&gt;($to);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $fromDom &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dom_import_simplexml&lt;/span&gt;($from);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $toDom&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;appendChild&lt;/span&gt;($toDom&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ownerDocument&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;importNode&lt;/span&gt;($fromDom, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;header&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Content-type: text/xml&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$orders&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleXMLElement&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&amp;lt;orders&amp;gt;&amp;lt;/orders&amp;gt; &amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;($i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;;$i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $order&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SimpleXMLElement&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&amp;lt;order&amp;gt;&amp;lt;/order&amp;gt; &amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$order&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;item&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;,$i);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;shoes&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;price&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;110.00&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sxml_append&lt;/span&gt;($orders,$order);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $orders&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;asXML&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上代码需要安装DOM扩展，&lt;a class="link" href="http://pt.php.net/manual/en/ref.simplexml.php#91561" target="_blank" rel="noopener"&#10; &gt;其他&lt;/a&gt;的方法都是循环将子SimpleXMLElement的子元素取出逐一添加，而实际上$order这个xml对象是从其他对象中获取的，上面的方法就方便多了。&lt;/p&gt;&#10;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/4778865/php-simplexml-addchild-with-another-simplexmlelement" target="_blank" rel="noopener"&#10; &gt;PHP – SimpleXML – AddChild with another SimpleXMLElement&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://weizhifeng.net/php-clone.html" target="_blank" rel="noopener"&#10; &gt;PHP克隆&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/zh/language.oop5.references.php" target="_blank" rel="noopener"&#10; &gt;PHP对象和引用&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.php.net/manual/zh/language.oop5.cloning.php" target="_blank" rel="noopener"&#10; &gt;PHP对象和复制&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP并发操作加锁</title><link>https://courages.us/php%E6%93%8D%E4%BD%9C%E5%8A%A0%E9%94%81/</link><pubDate>Thu, 21 Feb 2013 16:43:44 +0800</pubDate><guid>https://courages.us/php%E6%93%8D%E4%BD%9C%E5%8A%A0%E9%94%81/</guid><description>&lt;p&gt;有时候在PHP程序中同时只允许一个进程在操作或者只想让一个进程去执行，这时就需要加锁，在网络上找到了phplock这个项目。&lt;a class="link" href="http://code.google.com/p/phplock/" target="_blank" rel="noopener"&#10; &gt;phplock&lt;/a&gt;用于多进程模式下PHP并发操作加锁，以防止并发对同一文件的读写操作错误和缓存失效时，大量请求直接穿透到数据库，造成数据库压力宕机。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * PHPLock进程锁&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 本进程锁用来解决php在并发时候的锁控制&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 他根据文件锁来模拟多个进程之间的锁定，效率不是非常高。如果文件建立在内存中，可以大大提高效率。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * PHPLOCK在使用过程中，会在指定的目录产生$hashNum个文件用来产生对应粒度的锁。不同锁之间可以并行执行。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 这有点类似mysql的innodb的行级锁，不同行的更新可以并发的执行。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @link http://code.google.com/p/phplock/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @author sunli&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @blog http://sunli.cnblogs.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @svnversion $Id$&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @version v1.0 beta1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @license Apache License Version 2.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @copyright sunli1223@gmail.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHPLock&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//文件锁存放路径&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//文件句柄&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//锁粒度,设置越大粒度越小&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $hashNum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//cache key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//是否存在eaccelerator标志&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; $eAccelerator &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 构造函数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 传入锁的存放路径，及cache key的名称，这样可以进行并发&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param string $path 锁的存放目录，以&amp;#34;/&amp;#34;结尾&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param string $name cache key&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__construct&lt;/span&gt;($name,$path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;lock\\&amp;#39;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//判断是否存在eAccelerator,这里启用了eAccelerator之后可以进行内存锁提高效率&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eAccelerator&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;function_exists&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;eaccelerator_lock&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eAccelerator&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;path&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;_mycrc32&lt;/span&gt;($name) &lt;span style="color:#f92672"&gt;%&lt;/span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hashNum&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;.lock&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $name;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__destruct&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;unlock&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * crc32&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * crc32封装&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @param int $string&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * @return int&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_mycrc32&lt;/span&gt;($string)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $crc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;abs&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;crc32&lt;/span&gt;($string));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($crc &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x80000000&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $crc &lt;span style="color:#f92672"&gt;^=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xffffffff&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $crc &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; $crc;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 加锁&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Enter description here ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lock&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//如果无法开启ea内存锁，则开启文件锁&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eAccelerator&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//配置目录权限可写&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fp&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;w+&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fp&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;flock&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fp&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;LOCK_EX&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eaccelerator_lock&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * 解锁&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; * Enter description here ...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;unlock&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;eAccelerator&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fp&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;flock&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fp&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;LOCK_UN&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;clearstatcache&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fp&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eaccelerator_unlock&lt;/span&gt;($this&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试的代码&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;require&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;class.phplock.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$lock &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PHPLock&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;key_name&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;($lock&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;lock&lt;/span&gt;()){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//do something here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//进程安全的操作&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $lock&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;unlock&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//do something here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//使用过程中需要注意下文件锁所在路径需要有写权限.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意的是在部分操作系统中，flock() 以处理级执行。当用一个多线程服务器 API（比如 ISAPI）时，可能不可以依靠 flock() 来保护文件，因为在同一服务器内运行在其它线程的 PHP 脚本可以对该文件进行处理。&lt;br&gt;&#10;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://www.cnblogs.com/scotoma/archive/2010/09/26/1836312.html" target="_blank" rel="noopener"&#10; &gt;并发下常见的加锁及锁的PHP具体实现&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://code.google.com/p/phplock/" target="_blank" rel="noopener"&#10; &gt;phplock&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/325806/best-way-to-obtain-a-lock-in-php" target="_blank" rel="noopener"&#10; &gt;best way to obtain a lock in php&lt;/a&gt;&lt;/p&gt;</description></item><item><title>PHP异步执行长时间任务</title><link>https://courages.us/php%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%E5%90%8E%E5%8F%B0%E4%BB%BB%E5%8A%A1/</link><pubDate>Wed, 20 Feb 2013 18:22:57 +0800</pubDate><guid>https://courages.us/php%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%E5%90%8E%E5%8F%B0%E4%BB%BB%E5%8A%A1/</guid><description>&lt;p&gt;长时间执行的任务不适合放在PHP中执行应当放在任务调度系统或消息系统中由后台程序去执行，但是有时候还是需要在PHP中执行下长时间的任务 ，并且客户端不需要返回值。实现的思路大体如下：首先客户端发起一个不需要等待返回的请求，服务器端则需要忽略请求中断和执行时间，以免中途退出。&lt;/p&gt;&#10;&lt;p&gt;当有请求到达时，服务器端执行任务，在这里会产生一个文件。服务器端文件：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//ob_start();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//header(&amp;#39;Content-Type:text/html;charset=utf-8&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//header(&amp;#39;Connection:close&amp;#39;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//flush();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ignore_user_abort&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//忽略客户端连接中断&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;set_time_limit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//忽略页面执行超时&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//Todo:do something here&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sleep&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;fopen&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;dirname&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;__FILE__&lt;/span&gt; )&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\\&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;(), &lt;span style="color:#e6db74"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#75715e"&gt;#91;/php&amp;amp;#93;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;使用&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;http://php.net/manual/en/function.fsockopen.php&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;fsockopen&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;来请求服务端执行任务，该方法需要自己拼凑header，包括参数等&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;triggerRequest&lt;/span&gt;($url, $post_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(), $cookie &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;()){ &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $method &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;//可以通过POST或者GET传递一些参数给要触发的脚本 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $url_array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parse_url&lt;/span&gt;($url); &lt;span style="color:#75715e"&gt;//获取URL信息，以便平凑HTTP HEADER &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;isset&lt;/span&gt;($url_array&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#75715e"&gt;#91;&amp;#39;port&amp;#39;&amp;amp;#93;)? $url_array&amp;amp;#91;&amp;#39;port&amp;#39;&amp;amp;#93; : 80; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $fp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fsockopen&lt;/span&gt;($url_array&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#75715e"&gt;#91;&amp;#39;host&amp;#39;&amp;amp;#93;, $port, $errno, $errstr, 30); &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;$fp){ &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $getPath &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $url_array&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#75715e"&gt;#91;&amp;#39;path&amp;#39;&amp;amp;#93; .&amp;#34;?&amp;#34;. $url_array&amp;amp;#91;&amp;#39;query&amp;#39;&amp;amp;#93;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($post_data)){ &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $method &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $header &lt;span style="color:#f92672"&gt;=&lt;/span&gt; $method &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; $getPath; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $header &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; HTTP/1.1&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $header &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Host: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt; $url_array&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#75715e"&gt;#91;&amp;#39;host&amp;#39;&amp;amp;#93; . &amp;#34;\r\n &amp;#34;; //HTTP 1.1 Host域不能省略 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $header &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Connection:Close&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($cookie)){ &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $_cookie &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strval&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt;($cookie &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $k &lt;span style="color:#f92672"&gt;=--&amp;gt;&lt;/span&gt; $v){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $_cookie &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $k&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;=&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$v&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;; &amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $cookie_str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Cookie: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;base64_encode&lt;/span&gt;($_cookie) &lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//传递Cookie&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $header &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $cookie_str;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;empty&lt;/span&gt;($post_data)){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $_post &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strval&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt;($post_data &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; $k &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; $v){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $_post &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $k&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;=&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;$v&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;amp;&amp;#34;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $post_str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type: application/x-www-form-urlencoded&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//POST数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $post_str &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Length: &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;strlen&lt;/span&gt;($_post) &lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;&lt;span style="color:#75715e"&gt;//POST数据的长度&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $post_str &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $_post&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\r\n\r\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;&lt;/span&gt;; &lt;span style="color:#75715e"&gt;//传递POST数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $header &lt;span style="color:#f92672"&gt;.=&lt;/span&gt; $post_str;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fwrite&lt;/span&gt;($fp, $header);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fclose&lt;/span&gt;($fp);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;http://127.0.0.1/learn/asyn/server.php&amp;#39;&lt;/span&gt;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;triggerRequest&lt;/span&gt;($url);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2.使用&lt;a class="link" href="http://php.net/manual/en/book.curl.php" target="_blank" rel="noopener"&#10; &gt;curl&lt;/a&gt;来发起请求，可以方便的设置传递参数，cookie等，比fsockopen简洁许多，需要安装php_curl扩展&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $ch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;curl_init&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;array&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;param&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;curl_setopt&lt;/span&gt;($ch, &lt;span style="color:#a6e22e"&gt;CURLOPT_URL&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;http://127.0.0.1/learn/asyn/server.php&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;curl_setopt&lt;/span&gt;($ch, &lt;span style="color:#a6e22e"&gt;CURLOPT_POST&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;curl_setopt&lt;/span&gt;($ch, &lt;span style="color:#a6e22e"&gt;CURLOPT_POSTFIELDS&lt;/span&gt;, $data);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;curl_setopt&lt;/span&gt;($ch, &lt;span style="color:#a6e22e"&gt;CURLOPT_TIMEOUT&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);&lt;span style="color:#75715e"&gt;//1秒后立即执行&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;curl_exec&lt;/span&gt;($ch);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;curl_close&lt;/span&gt;($ch);&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以采用popen，ajax发起请求，详见参考链接。&lt;br&gt;&#10;参考链接&lt;br&gt;&#10;&lt;a class="link" href="http://php.net/manual/en/function.fsockopen.php" target="_blank" rel="noopener"&#10; &gt;fsockopen函数用法&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2008/04/16/98.html" title="Permanent Link to 使用fscok实现异步调用PHP"&#10; target="_blank" rel="noopener"&#10; &gt;使用fscok实现异步调用PHP&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.laruence.com/2008/04/14/318.html" title="Permanent Link to PHP实现异步调用方法研究"&#10; target="_blank" rel="noopener"&#10; &gt;PHP实现异步调用方法研究&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.leezhong.com/tech/2010/12/05/php-async.html" target="_blank" rel="noopener"&#10; &gt;说说php的异步请求&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://blog.51yip.com/php/1039.html" target="_blank" rel="noopener"&#10; &gt;php curl常用的5个例子&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>Nginx做简单的反向代理</title><link>https://courages.us/nginx%E5%81%9A%E7%AE%80%E5%8D%95%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/</link><pubDate>Fri, 15 Feb 2013 17:52:35 +0800</pubDate><guid>https://courages.us/nginx%E5%81%9A%E7%AE%80%E5%8D%95%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/</guid><description>&lt;p&gt;&lt;a class="link" href="http://nginx.org/cn/" target="_blank" rel="noopener"&#10; &gt;Nginx&lt;/a&gt;是一个HTTP和反向代理服务器，可做为反向代理实现负载均衡的例子，也可以作为代理服务器，也经常作为web服务器使用。如果一台服务器装有多个web服务器则必须监听多个端口，对于用户的访问将是不友好，则需要一个统一的前端来进行分发。本文只是简单的利用Nginx作为前端代理服务器，代理不同的后端服务器:IIS和Apache，实现不同的域名解析至不同的服务器。&lt;/p&gt;&#10;&lt;p&gt;首先更改IIS的监听端口为8000，Apache的监听端口为9000，保证Nginx占有80端口和443端口。然后更改nginx.conf添加以下内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name iis.localhost;#要代理的域名&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:8000/;#内部服务器实际地址和监听端口&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 80;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name apache.localhost;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:9000/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_redirect off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Real-IP $remote_addr;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进阶操作，可按照参照&lt;a class="link" href="http://www.vpsmm.com/blog/nginx-proxy-and-all-cache-config" target="_blank" rel="noopener"&#10; &gt;此文&lt;/a&gt;设置前端缓存，注意以下内容须放入http{}内&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_body_buffer_size 512k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_connect_timeout 5;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_read_timeout 60;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_send_timeout 5;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_buffer_size 16k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_buffers 4 64k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_busy_buffers_size 128k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_temp_file_write_size 128k;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_temp_path D:/nginx/temp;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache_path D:/nginx/cache levels=1:2 keys_zone=cache_one:256m inactive=7d max_size=1g;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再修改server中location{}的缓存设置如下&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache cache_one;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache_valid 200 304 3d;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;expires 10d;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://blog.csdn.net/omohe/article/details/4335765" target="_blank" rel="noopener"&#10; &gt;nginx做为反向代理实现负载均衡的例子&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.vpsmm.com/blog/nginx-proxy-and-all-cache-config" target="_blank" rel="noopener"&#10; &gt;Nginx反向代理&amp;amp;前端全缓存相关配置教程&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://www.ha97.com/5119.html" target="_blank" rel="noopener"&#10; &gt;（总结）Nginx与Apache、Tomcat、Resin动静分离核心配置&lt;/a&gt;&lt;/p&gt;</description></item><item><title>JasperReports flash打印实现</title><link>https://courages.us/jasperreports-flash%E6%89%93%E5%8D%B0%E5%AE%9E%E7%8E%B0/</link><pubDate>Thu, 14 Feb 2013 22:05:11 +0800</pubDate><guid>https://courages.us/jasperreports-flash%E6%89%93%E5%8D%B0%E5%AE%9E%E7%8E%B0/</guid><description>&lt;p&gt;&lt;a class="link" href="http://community.jaspersoft.com/project/jasperreports-library" target="_blank" rel="noopener"&#10; &gt;JasperReports&lt;/a&gt;是一个基于Java的开源报表工具，可以在ireport中进行设计后，输出HTML，PDF，Excell，OpenOffice和Word格式。JasperReports支持applet方式打印，但是flash方式却是注释掉的。在net\sf\jasperreports\flex\view\Viewer.mxml文件中&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;!--&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;22&amp;#34;&lt;/span&gt; toolTip&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Print Report&amp;#34;&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnPrintReport0&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; buttonMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;Embed&lt;span style="color:#f92672"&gt;(&lt;/span&gt;source&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;images/print.GIF&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;22&amp;#34;&lt;/span&gt; toolTip&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Print Report&amp;#34;&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnReload&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; buttonMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; click&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnReloadClick()&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;Embed&lt;span style="color:#f92672"&gt;(&lt;/span&gt;source&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;images/reload.GIF&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;--&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文主要完成JasperReports的flash打印功能，是基于JasperReports Flash Viewer 4.0.0修改，参考了网络上基于3.0版本的修改。将Viewer.mxml文件上面的文字修改为&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;22&amp;#34;&lt;/span&gt; toolTip&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Print Report&amp;#34;&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnPrintReport0&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; buttonMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;false&amp;#34;&lt;/span&gt; click&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnPrintReport()&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;Embed&lt;span style="color:#f92672"&gt;(&lt;/span&gt;source&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;images/print.GIF&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;!--&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;22&amp;#34;&lt;/span&gt; toolTip&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Print Report&amp;#34;&lt;/span&gt; id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnReload&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; buttonMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; click&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;btnReloadClick()&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;@&lt;/span&gt;Embed&lt;span style="color:#f92672"&gt;(&lt;/span&gt;source&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;images/reload.GIF&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;icon&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/&lt;/span&gt;mx&lt;span style="color:#f92672"&gt;:&lt;/span&gt;Button&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;--&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在Viewer.mxml中找到refreshPage函数，启用打印按钮，将&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pageCanvas:&lt;span style="color:#66d9ef"&gt;PageCanvas&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PageCanvas&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pageIndex&lt;span style="color:#f92672"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageCanvas&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;scaleX&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; zoomRatio&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageCanvas&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;scaleY&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; zoomRatio&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;visible&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;removeAllChildren&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;pageCanvas&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;visible&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改为&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pageCanvas:&lt;span style="color:#66d9ef"&gt;PageCanvas&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PageCanvas&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pageIndex&lt;span style="color:#f92672"&gt;]);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageCanvas&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;scaleX&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; zoomRatio&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageCanvas&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;scaleY&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; zoomRatio&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;visible&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;removeAllChildren&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;pageCanvas&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageBox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;visible&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btnPrintReport0&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在Viewer.mxml中引入net\sf\jasperreports\flex\view\PrintMananger.as文件，以支持打印&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; net.sf.jasperreports.flex.view.PrintManager&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在Viewer.mxml增加打印函数btnPrintReport&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;btnPrintReport&lt;/span&gt;&lt;span style="color:#f92672"&gt;():&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;PrintManager&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;printAll&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;jrpxmlUrl&lt;span style="color:#f92672"&gt;,&lt;/span&gt;pageFetchSize&lt;span style="color:#f92672"&gt;,&lt;/span&gt;report&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;net\sf\jasperreports\flex\view\PrintMananger.as文件内容&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-actionscript3" data-lang="actionscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;package&lt;/span&gt; net.sf.jasperreports.flex.view&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.events.EventDispatcher&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.events.SecurityErrorEvent&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.events.Event&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.events.ProgressEvent&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.core.UIComponent&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.collections.IList&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.collections.ArrayCollection&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; net.sf.jasperreports.flex.view.PageCanvas&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; net.sf.jasperreports.flex.model.Report&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; net.sf.jasperreports.flex.xml.ReportFactory&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.events.HTTPStatusEvent&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.net.URLLoader&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.net.URLRequest&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; flash.events.IOErrorEvent&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.printing.FlexPrintJobScaleType&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.printing.FlexPrintJob&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.core.Application&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.containers.VBox&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; mx.events.FlexEvent&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; PrintManager &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; EventDispatcher&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; url:&lt;span style="color:#66d9ef"&gt;String&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; urlLoader:&lt;span style="color:#66d9ef"&gt;URLLoader&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; report:&lt;span style="color:#66d9ef"&gt;Report&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pageIndex:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pageFetchSize:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; componentsToBeInitialized:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pagesPrint:&lt;span style="color:#66d9ef"&gt;Array&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;[];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; LOAD_PAGE:&lt;span style="color:#66d9ef"&gt;String&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;loadPage&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; ALL_PAGE:&lt;span style="color:#66d9ef"&gt;String&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;allPageLoader&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PrintManager&lt;/span&gt;&lt;span style="color:#f92672"&gt;(){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;get&lt;/span&gt; url&lt;span style="color:#f92672"&gt;():&lt;/span&gt;String&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; url&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; url&lt;span style="color:#f92672"&gt;(&lt;/span&gt;value&lt;span style="color:#f92672"&gt;:&lt;/span&gt;String&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;value&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; fetchSize&lt;span style="color:#f92672"&gt;(&lt;/span&gt;fetchSize&lt;span style="color:#f92672"&gt;:&lt;/span&gt;int&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;pageFetchSize &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fetchSize&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;printAll&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;url&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;String&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt;fetchSize&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt;report&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Report&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pm:&lt;span style="color:#66d9ef"&gt;PrintManager&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PrintManager&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pm&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;url&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; url&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;pm&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageFetchSize&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fetchSize&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;pm&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;report&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; report&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pm&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;loadAll&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;loadAll&lt;/span&gt;&lt;span style="color:#f92672"&gt;():&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;LOAD_PAGE&lt;span style="color:#f92672"&gt;,&lt;/span&gt; onLoadPage&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;ALL_PAGE&lt;span style="color:#f92672"&gt;,&lt;/span&gt; onAllPageLoaded&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;pageIndex&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; loadFlag:&lt;span style="color:#66d9ef"&gt;Boolean&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pageIndex &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(!&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pageIndex&lt;span style="color:#f92672"&gt;])&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;loadFlag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;pageIndex&lt;span style="color:#f92672"&gt;++;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;loadFlag&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;loadPage&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; removeEventListener&lt;span style="color:#f92672"&gt;(&lt;/span&gt;LOAD_PAGE&lt;span style="color:#f92672"&gt;,&lt;/span&gt; onLoadPage&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatchEvent&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;ALL_PAGE&lt;span style="color:#f92672"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;onLoadPage&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;e&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pageIndex&lt;span style="color:#f92672"&gt;++;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pageIndex &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;&lt;span style="color:#f92672"&gt;(!&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pageIndex&lt;span style="color:#f92672"&gt;]){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;loadPage&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; removeEventListener&lt;span style="color:#f92672"&gt;(&lt;/span&gt;LOAD_PAGE&lt;span style="color:#f92672"&gt;,&lt;/span&gt; onLoadPage&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dispatchEvent&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;ALL_PAGE&lt;span style="color:#f92672"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;onAllPageLoaded&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; cur:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; uc:&lt;span style="color:#66d9ef"&gt;UIComponent&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;var pj&lt;span style="color:#f92672"&gt;:*;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;&lt;span style="color:#f92672"&gt;){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;pj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FlexPrintJob&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;pj&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;printAsBitmap&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pj&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;start&lt;/span&gt;&lt;span style="color:#f92672"&gt;()){&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;cur &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;cur &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;uc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; processPage&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PageCanvas&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;cur&lt;span style="color:#f92672"&gt;]));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;Application&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;uc&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;pj&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addObject&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;uc&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;Application&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;application&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;removeChild&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;uc&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;cur&lt;span style="color:#f92672"&gt;++;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;pj&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;processPage&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;param1&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;PageCanvas&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;UIComponent&lt;/span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;var vbox&lt;span style="color:#f92672"&gt;:*&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;VBox&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;vbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;horizontalScrollPolicy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;off&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;vbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;verticalScrollPolicy&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;off&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;vbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;width&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageWidth&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;vbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;height&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageHeight&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;vbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setStyle&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;backgroundColor&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;#FFFFFF&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;vbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addChild&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;param1&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;vbox&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;loadPage&lt;/span&gt;&lt;span style="color:#f92672"&gt;():&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;URLLoader&lt;/span&gt;&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;Event&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;COMPLETE&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; completeHandler&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;Event&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;OPEN&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; openHandler&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;ProgressEvent&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PROGRESS&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; progressHandler&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;SecurityErrorEvent&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SECURITY_ERROR&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; securityErrorHandler&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;HTTPStatusEvent&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HTTP_STATUS&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; httpStatusHandler&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;IOErrorEvent&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;IO_ERROR&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; ioErrorHandler&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; goRight:&lt;span style="color:#66d9ef"&gt;Boolean&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; goLeft:&lt;span style="color:#66d9ef"&gt;Boolean&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; right:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; left:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;goRight &lt;span style="color:#f92672"&gt;||&lt;/span&gt; goLeft&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;goRight&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; left &lt;span style="color:#f92672"&gt;+&lt;/span&gt; right &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; pageFetchSize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pageIndex &lt;span style="color:#f92672"&gt;+&lt;/span&gt; right &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pageIndex &lt;span style="color:#f92672"&gt;+&lt;/span&gt; right &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;right&lt;span style="color:#f92672"&gt;++;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;goRight &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;goLeft&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; left &lt;span style="color:#f92672"&gt;+&lt;/span&gt; right &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; pageFetchSize&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pageIndex &lt;span style="color:#f92672"&gt;-&lt;/span&gt; left &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;pageIndex &lt;span style="color:#f92672"&gt;-&lt;/span&gt; left &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;left&lt;span style="color:#f92672"&gt;++;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&#9;goLeft &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;URLRequest&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;url &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;amp;startPage=&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pageIndex &lt;span style="color:#f92672"&gt;-&lt;/span&gt; left&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;amp;endPage=&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pageIndex &lt;span style="color:#f92672"&gt;+&lt;/span&gt; right&lt;span style="color:#f92672"&gt;)));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//first load; pageIndex == 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;URLRequest&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;url &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;amp;page=&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; pageIndex&lt;span style="color:#f92672"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;completeHandler&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; newReport:&lt;span style="color:#66d9ef"&gt;Report&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ReportFactory&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;create&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;XML&lt;span style="color:#f92672"&gt;(&lt;/span&gt;urlLoader&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; i:&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; pages:&lt;span style="color:#66d9ef"&gt;IList&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;pages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#75715e"&gt;//first load&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;report &lt;span style="color:#f92672"&gt;=&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;pages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ArrayCollection&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Array&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pageCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;startPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt; i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;endPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;;&lt;/span&gt; i&lt;span style="color:#f92672"&gt;++)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;pages&lt;span style="color:#f92672"&gt;[&lt;/span&gt;i&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;i &lt;span style="color:#f92672"&gt;-&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;startPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pages&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pages&lt;span style="color:#f92672"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;startPageIndex&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;min&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;startPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;startPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;endPageIndex&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Math&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;max&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;endPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; newReport&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;endPageIndex&lt;/span&gt;&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;refreshPage&lt;span style="color:#f92672"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;openHandler&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;trace&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;openHandler: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; event&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;progressHandler&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;ProgressEvent&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;trace&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;progressHandler loaded:&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; event&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bytesLoaded&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; total: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; event&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bytesTotal&lt;/span&gt;&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;securityErrorHandler&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;SecurityErrorEvent&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;trace&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;securityErrorHandler: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; event&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;httpStatusHandler&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;HTTPStatusEvent&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;trace&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;httpStatusHandler: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; event&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ioErrorHandler&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;event&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;IOErrorEvent&lt;/span&gt;&lt;span style="color:#f92672"&gt;):&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#a6e22e"&gt;trace&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ioErrorHandler: &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; event&lt;span style="color:#f92672"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function &lt;/span&gt;&lt;span style="color:#a6e22e"&gt;refreshPage&lt;/span&gt;&lt;span style="color:#f92672"&gt;():&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;report&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&#9;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dispatchEvent&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;Event&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;LOAD_PAGE&lt;/span&gt;&lt;span style="color:#f92672"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&#9;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译Main.mxml运行，即实现打印功能，但是包含图片的打印依然打印不出来。对于这种动态图片的打印添加了&lt;a class="link" href="http://stackoverflow.com/questions/7467914/flex-4-printing-problem-with-dynamic-components" target="_blank" rel="noopener"&#10; &gt;等待事件完成&lt;/a&gt;，仍能无效，不知道有没有好的实现。&lt;br&gt;&#10;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://sourceforge.net/projects/jasperreports/files/jasperreports-flash/" target="_blank" rel="noopener"&#10; &gt;JasperReports Library&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bbs.9ria.com/thread-37125-1-1.html" target="_blank" rel="noopener"&#10; &gt;完成Flex报表设计、生成、打印功能&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://stackoverflow.com/questions/7467914/flex-4-printing-problem-with-dynamic-components" target="_blank" rel="noopener"&#10; &gt;Flex 4 Printing Problem with dynamic components&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>PHP/Java Bridge笔记</title><link>https://courages.us/phpjava-bridge%E7%AC%94%E8%AE%B0/</link><pubDate>Thu, 14 Feb 2013 15:00:38 +0800</pubDate><guid>https://courages.us/phpjava-bridge%E7%AC%94%E8%AE%B0/</guid><description>&lt;p&gt;&lt;a class="link" href="http://php-java-bridge.sourceforge.net/pjb/" target="_blank" rel="noopener"&#10; &gt;PHP/Java Bridge&lt;/a&gt;是基于xml的网络协议的实现，该协议使得本地脚本语言引擎（ 比如PHP,Python）能够连接Java虚拟机。它比通过SOAP的RPC调用更快，更节省服务器资源；比直接的Java本地接口通信要更快和更可靠，不需要额外的组件。Java应用比PHP要多，组件和类库也比PHP要多，比如JasperReports，通过PHP/Java Bridge可以为PHP 所用，当然也可以采用其他方式进行调用,比如官方的SOAP示例。&lt;/p&gt;&#10;&lt;p&gt;网上的关于JavaBridge安装文章较旧，现在的JavaBridge安装已经不需要java.so或php_java.dll，只需要php安装版本大于5.0，JDK版本大于1.4.2。本文是将JavaBridge放在Tomcat下运行的，独立运行参照&lt;a class="link" href="http://bbs.phpchina.com/thread-108498-1-1.html" target="_blank" rel="noopener"&#10; &gt;此文&lt;/a&gt;设置。&lt;/p&gt;&#10;&lt;p&gt;将下载好的JavaBridge.war放入tomcat目录下的webapps下，启动Tomcat即可在webapps目录下看到JavaBridge文件夹，将JavaBridge下的java文件夹放到php的include目录（或程序运行目录）下。&lt;/p&gt;&#10;&lt;p&gt;打开http://127.0.0.1:8080/JavaBridge/运行示例，如果失败则可能是php未安装，解压版的可能导致失败如xampp。&lt;/p&gt;&#10;&lt;p&gt;在apache的网站目录下建立测试文件test.php，内容：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;java/Java.inc&amp;#34;&lt;/span&gt;); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;java&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;java.lang.System&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getProperties&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行http://127.0.0.1/test.php查看输出，能看到系统信息，则表示安装成功。对于Java中要提供给php调用的jar应放在tomcat\webapps\JavaBridge\WEB-INF\lib目录下。注意此时在php中不需要用java_require()函数请求所需的jar文件，否则会提示“&lt;strong&gt;Warning&lt;/strong&gt;: java_require() not supported anymore. ”。php中使用只需require(“java/Java.inc”)，然后用new Java()对应的类进行实例化，示例如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;php&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;java/Java.inc&amp;#34;&lt;/span&gt;); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//java_require(&amp;#34;Jphp.jar&amp;#34;);//新版本不再需要 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Java&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;); &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$java &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Java&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Jphp&amp;#34;&lt;/span&gt;); $java&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;setName&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Jphp&amp;#39;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;echo&lt;/span&gt; $java&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;();&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参考链接：&lt;br&gt;&#10;&lt;a class="link" href="http://php-java-bridge.sourceforge.net/pjb/index.php" target="_blank" rel="noopener"&#10; &gt;PHP/Java Bridge&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://newsletter.ascc.sinica.edu.tw/news/read_news.php?nid=1483" target="_blank" rel="noopener"&#10; &gt;詳全文_淺談PHP與Java之Web開發整合技術&lt;/a&gt;&lt;br&gt;&#10;&lt;a class="link" href="http://bbs.phpchina.com/thread-108498-1-1.html" target="_blank" rel="noopener"&#10; &gt;PHP通过php-java-bridge调用Java类中方法&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Hello,World!</title><link>https://courages.us/hello-world/</link><pubDate>Wed, 13 Feb 2013 08:21:50 +0800</pubDate><guid>https://courages.us/hello-world/</guid><description>&lt;p&gt;时间过的真快，仿佛没有留下什么，不如开个博客记录一下吧&lt;/p&gt;&#10;</description></item></channel></rss>