手记

wokerman / 协议小谈

在workerman中一共内置了5中协议,分别为http、text、frame、websocket和ws,当然你也可以直接使用tcp。

一个一个说。

ProtocolInterface

这是workerman为所有协议规定要实现的一个接口(当然你也可以不实现,但是必须实现其中3个方法),此接口定义了三个方法给worker和connection使用。

  • input() 用来验证客户端过来的数据是否合法,如果合法就返回其长度。
  • decode() 对收到的数据进行解码
  • encode() 将要发送的数据进行编码

从这里我们也看到对于一个协议而言,它规定着数据的规则以及数据何时结束。比如input负责结束,decode和encode负责数据的规则。

http

这是我们最常用的一个协议了,比如你如果要用workerman实现一个web服务器的功能,这是你需要使用甚至要进行扩展的协议。内置的http实现了基本的内容,比如

  • 对常用方法的支持
  • 对session \ cookie 的支持
  • 对富媒体内容的支持

关于方法workerman内置的http协议支持6种,有GET、POST、PUT、DELETE、HEAD和OPTIONS,我想经常做接口开发的你一定偷偷乐了,起码习惯使用restful的同学会很喜欢。而当你请求的方法非以上六种时,workerman会给你返回一个 HTTP/1.1 400 Bad Request 错误。

另外对于http请求,cookie和session必不可少,workerman在这点上也进行了支持,并且当判断PHP在cli模式下的时候会用HttpCache类来辅助实现session功能。

另外有一点要注意的是,当我们客户端给服务器端发送POST请求的时候,workerman的http协议可以识别请求内容类型为multipart/form-data、application/json和application/x-www-form-urlencoded三种类型。

也就是说表单提交、文件上传和json格式的接口服务,workerman的http都可以正确解析。

text和frame

text/frame是两种相对比较简单的协议,我所说的简单是指协议规则,看下面

协议规则

  • text 数据包+换行符
  • frame 总包长+包体

对于数据包内容并没有太多限制,text/frame只是规定了数据包的边界。

因此当服务器上多个worker进行内部通讯的时候,text/frame是个很好的选择,简单快捷。

另外text/frame对数据包的不限制也决定了其灵活性,当我们做一个应用的时候,你发现使用websocket太麻烦的时候,text/frame是一个很好的选择。

当然你也可以按照text/frame的规范去自定义自己的协议。

websocket 和 ws

我想很多人都是因为要实现websocket通讯而选择了workerman,在这点上workerman对其有很好的支持,你只需要如下代码就完成了websocket通讯的服务器端部署。

require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;

$serverWorker = new Worker("websocket://127.0.0.1:1234");
$serverWorker->count = 1;
$serverWorker->name = "server";

$serverWorker->onMessage = function($connection, $data) {
    $connection->send("你好,客户端worker,我收到了。");
};

Worker::runAll();

是不是很简单,只需要指定Worker的通讯协议为websocket,其他就是worker的业务代码了。

而websocket客户端一般是浏览器、小程序等,它们会发起websocket通讯请求,比如下面是一段最简单的websocket在浏览器上的应用。

var ws = new WebSocket("ws://127.0.0.1:1234");
ws.onopen=function(evt){
    ws.send("你好,workerman");
};
ws.onmessage=function(evt){
    ws.close();
};
ws.onclose=function(evt){
    console.log("链接关闭");
};

值得注意的是,当使用H5的WebSocket对象时,对于要请求连接的通讯地址我们需要ws开头。

-----我是分割线-----

突然你的老板说我要用workerman来实现websocket的客户端,小李你去整一整。

这里要告诉你,websocket协议只能用于workerman的服务器端配置,当workerman来实现websocket的客户端的时候,需要用到ws协议。

就必须下面的这段实现代码,我们新建一个worker并在其启动过程中新建tcp链接来模拟websocket。

$worker = new Worker();
$worker->name = 'client';
// 进程启动时
$worker->onWorkerStart = function()
{

    $ws_connection = new AsyncTcpConnection("ws://127.0.0.1:1234");

    $ws_connection->onConnect = function($connection){
        $connection->send('你好服务器端');
    };

    $ws_connection->onMessage = function($connection, $data){
        echo "我是客户端,我收到了服务器端信息,内容是: $data\n";
    };

    $ws_connection->onError = function($connection, $code, $msg){
        echo "error: $msg\n";
    };

    $ws_connection->onClose = function($connection){
        echo "connection closed\n";
    };

    $ws_connection->connect();
};

要注意的是,当我们使用ws协议让workerman作为websocket客户端的时候,需要使用AsyncTcpConnection来模拟。

小结

以上就是workerman内置协议的讲解,更详细的可以看我原创课程,学好协议是我们接下来学习worker类的基础。

0人推荐
随时随地看视频
慕课网APP

热门评论

在tp5中 workerman服务端写在 push模块的某个控制器里,想在 index模块的某个控制器中调用 workerman服务端的方法,比如$ con-> send(),主动向客户端发送消息,请问要怎么做呀!就是想把连接成功后的对象存起来,给其它模块控制器调用,尝试过 global,文件缓存把对象存起来, global后打印出来是 null,文件缓存也不行

查看全部评论