关于php:Workerman的使用

10次阅读

共计 4582 个字符,预计需要花费 12 分钟才能阅读完成。

Workerman 是什么?
Workerman 是一款纯 PHP 开发的开源高性能的 PHP socket 服务框架。
Workerman 不是反复造轮子,它不是一个 MVC 框架,而是一个更底层更通用的 socket 服务框架,你能够用它开发 tcp 代理、梯子代理、做游戏服务器、邮件服务器、ftp 服务器、甚至开发一个 php 版本的 redis、php 版本的数据库、php 版本的 nginx、php 版本的 php-fpm 等等。Workerman 能够说是 PHP 畛域的一次翻新,让开发者彻底解脱了 PHP 只能做 WEB 的解放。实际上 Workerman 相似一个 PHP 版本的 nginx,外围也是多过程 +Epoll+ 非阻塞 IO。Workerman 每个过程能维持上万并发连贯。因为自身常住内存,不依赖 Apache、nginx、php-fpm 这些容器,领有超高的性能。同时反对 TCP、UDP、UNIXSOCKET,反对长连贯,反对 Websocket、HTTP、WSS、HTTPS 等通信协定以及各种自定义协定。领有定时器、异步 socket 客户端、异步 Mysql、异步 Redis、异步 Http、异步音讯队列等泛滥高性能组件。

Workerman 的一些利用方向

Workerman 不同于传统 MVC 框架,Workerman 不仅能够用于 Web 开发,同时还有更广大的应用领域,例如即时通讯类、物联网、游戏、服务治理、其它服务器或者中间件,这无疑大大提高了 PHP 开发者的视线。目前这些畛域的 PHP 开发者奇缺,如果想在 PHP 畛域有本人的技术劣势,不满足于每天的增删改查工作,或者想向架构师方向或者技术大牛的方向倒退,Workerman 都是十分值得学习的框架。倡议开发者不仅会用,而且能基于 Workerman 开发出属于本人的开源我的项目,晋升技能减少本人的影响力,比方 Beanbun 多过程网络爬虫框架就是一个很好的例子,刚刚上线不久就取得泛滥好评。
Workerman 的一些利用方向如下:
1、即时通讯类
例如网页即时聊天、即时消息推送、微信小程序、手机 app 音讯推送、PC 软件音讯推送等等
[示例 workerman-chat 聊天室、web 音讯推送、小蝌蚪聊天室]
2、物联网类
例如 Workerman 与打印机通信、与单片机通信、智能手环、智能家居、共享单车等等。
[客户案例如 易联云、易泊时代等]
3、游戏服务器类
例如棋牌游戏、MMORPG 游戏等等。[示例 browserquest-php]
4、HTTP 服务
例如 写高性能 HTTP 接口、高性能网站。如果想要做 HTTP 相干的服务或者站点强烈推荐 webman
5、SOA 服务化
利用 Workerman 将现有业务不同性能单元封装起来,以服务的模式对外提供对立的接口,达到零碎松耦合、易保护、高可用、易伸缩。[示例 workerman-json-rpc、workerman-thrift]
6、其它服务器软件
例如 GatewayWorker,PHPSocket.IO,http 代理,sock5 代理,分布式通信组件,分布式变量共享组件,音讯队列、DNS 服务器、WebServer、CDN 服务器、FTP 服务器等等
7、中间件
例如异步 MySQL 组件,异步 redis 组件,异步 http 组件,异步音讯队列组件,异步 dns 组件,文件监控组件,还有很多第三方开发的组件框架等等
显然传统的 mvc 框架很难实现以上的性能,所以也就是 workerman 诞生的起因。

上面应用 workerman 建设 websocket 连贯,实现一个简略的聊天事例。

下载 workerman 源码包
在 start.php 中引入源码,将源码包 vendor 目录放在与 start.php 同级目录

  1. start.php 代码如下:
    <?php
    require_once ‘vendor/autoload.php’;
    use Workerman\Worker;
    /**

    • 多端口,多协定
      */

    // 应用 websocket 协定
    $ws_worker = new Worker(“websocket://0.0.0.0:10086”);
    // 启动过程对外服务。如果过程启动后建设一个外部通信端口,则过程数必须为 1$ws_worker->count = 1;
    // 连贯事件, 阻断非法连贯
    $ws_worker->onConnect = function ($connection) use ($domains){
    };
    // 过程启动后建设一个外部通信端口
    $ws_worker->onWorkerStart = function ($ws_worker){
    $inner_text_worker = new Worker(“Text://0.0.0.0:10087”);
    $inner_text_worker->onMessage = function ($connection, $buffer) use ($ws_worker)
    {

     $data = json_decode($buffer, true);
     $id   = $data['id'];
     // 通过 workerman 向 id 的页面推送数据 
     $ret = sendMessageById($id, $buffer);
     // 返回推送后果
     $connection->send($ret ? 'ok' : 'fail');

    };
    $inner_text_worker->listen();
    $inner_text_worker = new Worker(“http://0.0.0.0:10087”);
    $inner_text_worker->onMessage = function ($http) use ($ws_worker)
    {

     $id = $_POST['id'];
     $status = $_POST['status'];
     // 通过 workerman 向 id 的页面推送数据 
     $ret = sendMessageById($id, ['id', 'status' => $status]);
     // 返回推送后果
     $http->send($ret ? 'ok' : 'fail');

    };
    $inner_text_worker->listen();};
    // 减少一个属性,用来保留 uid 到 connection 的映射
    $ws_worker->uidConnetions = [];// 客户端发送音讯时回调
    $ws_worker->onMessage = function ($connection, $data) use ($ws_worker){
    // 判断以后客户端是否曾经验证过
    if (!isset($connection->uid)) {

     $connection->uid = $data;
     $ws_worker->uidConnetions[$connection->uid] = $connection;
     return;

    }};
    // 当客户端连贯断开时
    $ws_worker->onClose = function ($connection) use ($ws_worker){
    if (isset($connection->uid)) {

     unset($ws_worker->uidConnetions[$connection->uid]);

    }};
    /**

    • sendMessageById 向指定的客户端推送数据
    • @param mixed $id
    • @param mixed $message
    • @access public
    • @return bool
      */

    function sendMessageById($id, $message){
    if (is_array($message))

     $message = json_encode($message);

    global $ws_worker;
    if (isset($ws_worker->uidConnetions[$id])) {

     $connection = $ws_worker->uidConnetions[$id];
     $connection->send($message);
     return true;

    }
    return false;}
    /**

    • broadcast 向所有用户推送数据
    • @param mixed $message
    • @access public
    • @return void
      */

    function broadcast($message){
    global $ws_worker;
    foreach ($ws_worker->uidConnetions as $connection) {

     $connection->send($message); 

    } }

Worker::runAll();

2. 开启服务过程:php start.php start

  1. 发送 http 申请到对应的端口, 代码如下:
    function post($url, $data = [], $timeout = 3){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 设置超时
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;}
    }
    // 发送 http 申请到 http 服务
    $data[‘id’] = 100;$data[‘status’] = 6;
    // 你的 IP 地址 + 端口号
    $url = ‘http://192.168.16.101:10087’;
    $result = post($url, $data);echo $result . “\n”;

4. 客户端连贯代码:
<!DOCTYPE html>
<html lang=”en”><head>

<meta charset="UTF-8">
<title>WebSocket_client</title>
<script>
    // 创立一个 socket 实例
    ws = new WebSocket("ws://192.168.16.101:10086");
    ws.onopen = function () {console.log("连贯胜利");
        ws.send(100);
        //console.log("发送数据:tom")

    };
    ws.onmessage = function (e) {console.log("收到服务端信息:" + e.data);
    };
    

</script>
</head>
<body>
</body>
</html>

crmeb 常识付费零碎的直播性能就是应用了 workerman+websocket 性能实现的,application\push\controller\Push.php 文件就是 workerman 的初始文件。public/wap/first/zsff/js/Websocket.js 为 websocket 性能文件。如果须要二开直播间互动性能,能够通过这两个文件批改。
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点 star: http://github.crmeb.net/u/defu 不胜感激!

正文完
 0