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流
  • 局域网流服务器迁移到手机上, 方便携带出门

最终要达到的效果

真人版吃鸡!

Windows    2018-04-20 15:45:00    133    0    0

Win10 后台运行进程

  1. //Win10 后台运行进程
  2. Start-Process php test.php -WindowStyle Hidden
  3. // 或
  4. start php test.php -WindowStyle Hidden
2018-03-12 16:45:41    174    0    0

根据key赋值

  1. $field = ['id', 'token'];
  2. $info = array_intersect_key((array)$obj, array_flip($field));
  3. print_R($info);
  4. /*
  5. $info['id'] = $obj->id;
  6. $info['token'] = $obj->token;

对多维数组中任意键值排序

  1. $array = [
  2. [
  3. 'order' => '2',
  4. 'name' => '小红',
  5. ],
  6. [
  7. 'order' => '1',
  8. 'name' => '小蓝',
  9. ],
  10. [
  11. 'order' => '3',
  12. 'name' => '小黑',
  13. ],
  14. ];
  15. array_multisort(array_column($array, 'order'), SORT_ASC, $array);
  16. print_R($array);

实现JS的 charCodeAt

  1. //实现JS的 charCodeAt
  2. function charCodeAt($str)
  3. {
  4. $result = '';
  5. for($i = 0, $l = mb_strlen($str, 'utf-8');$i < $l;++$i)
  6. {
  7. $result .= uniord(mb_substr($str, $i, 1, 'utf-8'));
  8. }
  9. return $result;
  10. }
  11. function uniord($str)
  12. {
  13. if (strlen($str) == 1){
  14. return hts(1^ord($str));
  15. }
  16. $str = mb_convert_en
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-11-14 10:37:33    168    0    0

自己写了一遍并不对

  1. function getAllFile($path)
  2. {
  3. $lists = scandir($path);
  4. unset($lists[0]);
  5. unset($lists[1]);
  6. foreach($lists as $file){
  7. $file = $path.'/'.$file;
  8. if (is_dir($file)){
  9. yield getAllFile($file);
  10. } else {
  11. yield $file;
  12. }
  13. }
  14. }

百度了以后差点笑出声

  1. function getAllFile($path)
  2. {
  3. $lists = scandir($path);
  4. unset($lists[0]);
  5. unset($lists[1]);
  6. foreach($lists as $file){
  7. $file = $path.'/'.$file;
  8. if (is_dir($file)){
  9. foreach(getAllFile($file) as $file){
  10. yield $file;
  11. }
  12. } else {
  13. yield $file;
  14. }
  15. }
  16. }
JS    2017-10-14 09:01:08    172    0    0

  1. var tmp = new Date();
  2. function f() {
  3. console.log(tmp);
  4. if (false) {
  5. var tmp = 'hello world';
  6. }
  7. }
  8. f(); // undefined

作用域内先使用后声明,即使不会运行也会覆盖之前变量

  1. function f1() {
  2. let n = 5;
  3. if (true) {
  4. let n = 10;
  5. }
  6. console.log(n); // 5
  7. }

ES6 的块级作用域解决了这个问题

块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了

  1. // IIFE 写法
  2. (function () {
  3. var tmp = ...;
  4. ...
  5. }());
  6. // 块级作用域写法
  7. {
  8. let tmp = ...;
  9. ...
  10. }