分类 - 程序

Swoft PHP RPC TCP    2018-06-07 15:15:31    265    0    0

前两篇教大家如何搭建和使用Swoft RPC 服务, 这里简单说一下如何用其他TCP 客户端如何调用Swoft 的RPC 服务

这里用swoole_client 举个例子

  1. $client = new \swoole_client(SWOOLE_SOCK_TCP);
  2. if (! $client->connect('192.168.1.214', 8099, 0.5))
  3. {
  4. return "connect failed. Error: {$client->errCode}\n";
  5. }
  6. $client->send(json_encode([
  7. "interface" => "App\Lib\MemberInterface",
  8. "version" => "0",
  9. "method" => "getMemberByID",
  10. "params" => [$mid],
  11. ]));
  12. $result = $client->recv();
  13. $client->close();
  14. return $result;

非常的简单易用, 但是需要注意一点:

interface 参数是服务端带命名空间的类名, 跟客户端没任何关系, 完全在于服务端把RPC 接口类放在哪儿...

Swoft PHP Swoole    2018-06-06 14:59:04    274    0    0

上一篇讲了如何用Swoft 搭建RPC 服务

本篇介绍如何使用微服务

微服务流程

首先讲一下微服务的流程

弄清楚流程, 开发起来就行云流水

这是官方给出的目录结构

  1. app/
  2. - Lib/ // 服务的公共接口定义目录,里面通常只有php接口类
  3. - Pool/ // 服务池配置,里面可以配置不同服务的连接池,参考里面的 UserServicePool
  4. - Services/ // 具体的服务接口实现类,里面的类通常实现了 Lib 中定义的接口

当然在多个服务中使用时, 要将lib库 app/Lib移到一个公共的git仓库里,然后各个服务通过 composer 来获取使用

这里有3个目录

Lib 是接口, 也是客户端和服务端必须的, 用来规定数据结构, 一般由服务端提供

服务端还需要实现Services, 也就是相当于Model

客户端可以通过配置Pool 来调用对应的Services, 如同调用自身的Model 一样方便

整个流程不是很难理解, 但是官方把三个目录放在一起, 并且没有详细说明, 导致很多同学搞不清楚

下面我们来写一个例子试一下吧

定义一个接口

接口定义和普通接口完全一致,唯一不一样的是
- 需要在类注释上定义类似 deferGetUser 方法,对应类里面方法 getUser 且首字母大写。这种 defer* 方法,一般用于业务延迟收包和并发使用。
- 这些方法是不需要实现的,仅用于提供IDE提示。内部调用逻辑由框架帮你完成

app/Lib 新建接口文件MemberInterface

定义一个getMemberByID方法, 并且根据官方提示, 在接口注释里定义一个deferGetMemberByID 方法

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: zcm
  5. * Date: 2018/6/6
  6. * Time: 16:01
  7. */
  8. namespace App\Lib;
  9. use Swoft\Core\ResultInterface;
  10. /**
  11. * Interface MemberInterf
PHP Swoft Swoole 微服务    2018-06-06 10:08:04    276    0    0

序言

Swoft Framework
基于 Swoole 原生协程的新时代 PHP 全栈式协程框架

Swoft 是什么?

Swoft 框架是首个基于Swoole 原生协程的新时代 PHP高性能协程全栈框架,内置协程网络服务器及常用的协程客户端,常驻内存,不依赖传统的 PHP-FPM

全异步非阻塞 IO 实现,以类似于同步客户端的写法实现异步客户端的使用,没有复杂的异步回调,没有繁琐的 yield,有类似 Go 语言的协程,灵活的注解

强大的全局依赖注入容器、完善的服务治理、灵活强大的 AOP、标准的 PSR 规范实现等

上面是官网描述, 感觉太官方, 我总结一下:

  • 常驻内存
  • 协程
  • 学习曲线平滑
  • 国内框架
  • 开箱即用的RPC

如何搭建微服务?

首先确保已经可以正确搭建Swoft

不清楚的可以查看Swoft 官方文档

鉴于每个人的开发环境都不同

这里选用官方Docker 作为开发环境

拉Docker 镜像

  1. docker pull swoft/swoft

非常的简单
title
这样就是成功了

为了方便理解

我们把swoft 复制两份

命名为swoft-rpcswoft-http

swoft-rpc只开启TCP 服务
swoft-http只开启Http 服务

修改配置文件

把根目录的.env.example复制一份为.env

.env 文件为swoft 配置文件, 最高优先级(覆盖config 下配置)

http 用到的配置

  1. # Server
  2. PFILE=/tmp/swoft.pid
  3. PNAME=php-swoft
  4. TCPABLE=false //是否同时启动TCP 服务器,这里用不到改为false
  5. CRONABLE=false
  6. AUTO_RELOAD=true
  7. AUTO_REGISTER=false
  8. ...
  9. # HTTP
  10. HTTP_HOST=0.0.0.0 //监听的网卡
  11. HTTP_PORT=80 //监听的端口
  12. HTTP_MODE=SWOOLE_PROCESS //不用管
  13. HTTP_TYPE=SWOOLE_SOCK_TCP //不用管
  14. .
2018-06-01 15:55:04    163    0    0

开新坑啦!

大概流程是

  • 自拍杆绑定到身后上方
  • 手机开启VR 直播模式
  • RTMP 协议推流到局域网服务器
  • VR 眼镜拉RTMP 流数据

待解决的几点

  • 延迟, 据说RTMP 协议延迟很大
  • VR 客户端拉RTMP流
  • 局域网流服务器迁移到手机上, 方便携带出门

最终要达到的效果

真人版吃鸡!

PHP Swoole    2017-12-04 10:12:53    263    0    0

公司里很多网站都是ThinkPHP框架

研究了下如何用Swoole 加载ThinkPHP框架

方向很明确 , onWorkerStart 里加载框架

onRequest 里调用每次请求入口

下面顺着文件一点点看吧


首先是入口文件 /public/index.php

  1. // 定义应用目录
  2. define('APP_PATH', __DIR__ . '/../application/');
  3. // 加载框架引导文件
  4. require __DIR__ . '/../thinkphp/start.php';

对我们有用的只有APP_PATH , 继续往下看/thinkphp/start.php

  1. namespace think;
  2. // ThinkPHP 引导文件
  3. // 加载基础文件
  4. require __DIR__ . '/base.php';
  5. // 执行应用
  6. App::run()->send();

这里就是我们需要的两个方面了 , 加载框架和请求入口

onWorkerStartrequire __DIR__ . '/base.php'
onRequestApp::run()->send()

好了 , 必要条件已经齐了 , 开始写吧

框架根目录下创建文件swooleServer.php(可以随意命名)

  1. <?php
  2. // 调试模式开关
  3. define("APP_DEBUG", true);
  4. // 定义应用目录
  5. define('APP_PATH', __DIR__ .'/application/');
  6. class server
  7. {
  8. private $serv;
  9. public function __construct(){
  10. $this->serv = new swoole_http_server("0.0.0.0", 9503);
  11. $this->serv->set([
  12. 'worker_num' => 2,
  13. 'dispatch_mode' => 2,
  14. ]);
  15. $this->serv->on('WorkerStart', array($this, '
2017-11-16 18:21:56    297    0    0

自己在前端的路上越走越远了.....


封装一下ajax

  1. var ajax = async (url, body, data = {}) => {
  2. let _data = {
  3. credentials : 'include',
  4. method: "POST",
  5. headers: {
  6. "Content-Type": "application/x-www-form-urlencoded"
  7. },
  8. body : '',
  9. },
  10. http_build_query = (obj) => {
  11. let param = [];
  12. for(let [k, v] of Object.entries(obj)){
  13. param.push(`${k}=${v}`);
  14. }
  15. return param.join('&');
  16. }
  17. Object.assign({}, _data, data);
  18. if (typeof(body) == 'object'){
  19. body = http_build_query(body);
  20. }
  21. _data.body += body;
  22. return (await fetch(url, _data)).text();
  23. }

代码里的_body_data 可以填写缺省值, 不需要的删掉也可以

以百度为例
同步ajax 可以这样写

  1. a = 3;
  2. while(a--){
  3. let result = await ajax('/', {
  4. path:"vega/GET/mtllist/idea"
  5. });
  6. console.log(result);
  7. }

title

result 就是返回值

异步的更简单

  1. a = 3;
  2. while(a--){
  3. ajax('/', {
  4. path:"vega/GET/mtllist/idea"
  5. }).then((result) => {
  6. conso
2017-09-15 15:40:19    220    0    0

也就是[1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 8]...这样子

不重复的7位数组, 那么和原数组的差集也是不重复的3位数组

需求可以简化为

1-10中输出全部不重复3位数组,取差集

也就是求[1, 2, 3], [1, 2, 4]...全部3位数组

思路很简单,每次遍历只需要输出比自身大的范围

比如k1 = 2 ,那么k2范围为3 - 10,k3k2 - 10

实现代码如下

  1. <?php
  2. $arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  3. $onlyArray = new OnlyArray($arr);
  4. print_R($onlyArray->getAllOnlyArray());
  5. class OnlyArray
  6. {
  7. private $range = [];
  8. private $result = [];
  9. public function __construct($range, $layer = 3)
  10. {
  11. $this->range = $range;
  12. $this->layer = $layer;
  13. $this->tmp1 = $range;
  14. }
  15. //生成一个不重复数组
  16. public function getAllOnlyArray()
  17. {
  18. //逐渐缩小k1的范围
  19. // while($k1 = array_shift($this->tmp1)){
  20. // $this->tmp2 = $this->tmp1;
  21. // //逐渐缩小k2的范围
  22. // while($k2 = array_shift($this->tmp2)){
  23. // //遍历k3
  24. // foreach($this->tmp2 as $k3){
  25. // $this->result[] =array_diff($thi
2017-08-15 16:12:16    183    0    0

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: zhangyue
  5. * Date: 2017/4/11
  6. * Time: 下午9:32
  7. */
  8. //设计公共接口
  9. interface Visit
  10. {
  11. public function go();
  12. }
  13. //实现不同交通工具类
  14. class Leg implements Visit
  15. {
  16. public function go()
  17. {
  18. echo "walt to Tibet!!";
  19. }
  20. }
  21. class Car implements Visit
  22. {
  23. public function go()
  24. {
  25. echo "drive car to Tibet!!";
  26. }
  27. }
  28. class Train implements Visit
  29. {
  30. public function go()
  31. {
  32. echo "go to Tibet by train!!";
  33. }
  34. }
  35. //设计容器类,容器类装实例或提供实例的回调函数
  36. class Container
  37. {
  38. //用于装提供实例的回调函数,真正的容器还会装实例等其他内容
  39. //从而实现单例等高级功能
  40. protected $bindings = [];
  41. //绑定接口和生成相应实例的回调函数
  42. public function bind($abstract, $concrete = null, $shared = false)
  43. {
  44. if (!$concrete instanceof Closure) {
  45. //如果提供的参数不是回调函数,则产生默认的回调函数
  46. $concrete = $this->getClosure($abstract, $concrete);
  47. }
  48. $this->bindings[$abstract] = compact('concrete', 'shared');
  49. }
  50. //默认生成实例的回调函数
  51. protected function getClosure($abstract, $co
PHP    2017-08-15 16:08:40    140    0    0

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: zhangyue
  5. * Date: 2017/4/12
  6. * Time: 下午9:50
  7. *
  8. * 请求处理管道
  9. *
  10. */
  11. interface Middleware{
  12. public static function handle(Closure $next);
  13. }
  14. class VerifyCsrfToken implements Middleware {
  15. public static function handle(Closure $next)
  16. {
  17. echo "验证Csrf Token<br/>" . PHP_EOL;
  18. $next();
  19. }
  20. }
  21. class ShareErrorsFromSession implements Middleware {
  22. public static function handle(Closure $next)
  23. {
  24. echo "如果session中有'errors'变量,则共享它<br/>" . PHP_EOL;
  25. $next();
  26. }
  27. }
  28. class StartSession implements Middleware {
  29. public static function handle(Closure $next)
  30. {
  31. echo "开启session,获取数据<br/>" . PHP_EOL;
  32. $next();
  33. echo "保存数据,关闭session<br/>" . PHP_EOL;
  34. }
  35. }
  36. class AddQueuedCookiesToResponse implements Middleware {
  37. public static function handle(Closure $next)
  38. {
  39. $next();
  40. echo "添加下次请求需要的cookie<br/>" . PHP_EOL;
  41. }
  42. }
  43. class
2017-08-12 14:31:39    238    0    0

之前所说的微信内置浏览器会代理用户,用这个可以防止微信代理

原理很简单,微信只代理GET和4K以下的POST,那就把所有A标签改成POST,Form追加内容


  1. window.onload = function(){
  2. var doc = document
  3. ,wxframe = {
  4. createForm : function(){
  5. this.form = doc.createElement('form')
  6. ,this.additional = doc.createElement('input');
  7. var weight = ' '
  8. ,i = 3
  9. ,input = this.additional
  10. input.type = 'hidden';
  11. input.name = ' ';
  12. while(i--){
  13. weight = weight.replace(/./g, function(a,b){
  14. return ' ';
  15. });
  16. }
  17. input.value = weight;
  18. this.form.method = 'POST';
  19. }
  20. ,each : function(array, method){
  21. var i = array.length
  22. while(i--){
  23. method(array[i]);
  24. }
  25. }
  26. ,init : function(){
  27. this.createForm();
  28. wxframe.each(doc.byTagName('form'), function(the