使用WorkerMan的第一步就是要和客户端商定应用层通信协议。
传统PHP开发都是基于Web的,基本上都是HTTP协议,HTTP协议的解析处理都由WebServer独自承担了,所以开发者不会关心协议方面的事情。然而当我们需要基于非HTTP协议开发时,传统WebServer无法满足我们的需求,这时需要基于WorkerMan开发,WorkerMan无法预先知道开发者所用的协议,所以需要开发者实现协议解析部分。
实际上制定自己的协议是比较简单的事情。简单的协议一般包含两部分:
数据大小标识主要是为了区分出TCP流中的每个请求边界。由于TCP是基于流的,服务端收到客户端的请求可能是不完整的,也可能是多个请求连在一起的。
假如使用"\n"作为区分数据边界的标识,有两个请求"ABC\n" 和 "EFG\n"先后发送给服务端,由于TCP分片等机制,服务端获取的数据可能的情况有以下两种:
对于收到"AB"这种不完整的情况,应该继续等待剩余请求数据到来再处理这个请求(在dealInput中返回1,说明这个请求还要等待一个字节)
对于"ABC\nEFG\n"这样的请求,我们需要逐个字节读取(在dealInput中返回1,说明这个请求还要读取一个字节),直到读取到"\n"字符,然后处理这个请求。处理完毕后WorkerMan发现Socket缓冲区还有请求数据没读取,同样逐个字节读取,直到读取到"\n"后处理对应请求。
传输的内容是按照商定的能识别格式传递的。例如定义一个通信协议的数据格式是json,区分边界的标识是"\n",则一个请求的数据包可能是这样的 {"module":"user","action":"get"}\n
。当服务端收到这个请求时,去掉请末尾"\n",用json_decode便可以得到客户端传递实际请求。
1、"\n"作为数据边界标识,数据格式为json
{"module":"user","action":"get"}\n
2、首部四个字节是以网络字节序pack的int值,标识请求数据包长度,数据格式为普通文本
$pack_len = pack('N', strlen('我是要请求的普通文本数据');
$pack_len.'我是要请求的普通文本数据'
3、首部10个字节明文数字表示数据包长度,空白位以0代替,数据格式为xml
0000000121<?xml version="1.0" encoding="ISO-8859-1"?>
<request>
<module>user</module>
<action>getInfo</action>
</request>
其中0000000121代表请求数据长度为121个字节,也就是整个请求的数据长度