美微书签收藏的网页

美微书签和网页 http://doc.workerman.net/dev/protocols.html 的作者无关,不对其内容负责。美微书签快照谨为网络故障时之索引,不代表被收藏的网页即时页面。
制定协议 |

制定协议

使用WorkerMan的第一步就是要和客户端商定应用层通信协议。

为什么要制定协议?

传统PHP开发都是基于Web的,基本上都是HTTP协议,HTTP协议的解析处理都由WebServer独自承担了,所以开发者不会关心协议方面的事情。然而当我们需要基于非HTTP协议开发时,传统WebServer无法满足我们的需求,这时需要基于WorkerMan开发,WorkerMan无法预先知道开发者所用的协议,所以需要开发者实现协议解析部分。

如何制定协议?

实际上制定自己的协议是比较简单的事情。简单的协议一般包含两部分:

  • 区分数据边界的标识
  • 数据格式定义

1、区分数据边界的标识

作用

数据大小标识主要是为了区分出TCP流中的每个请求边界。由于TCP是基于流的,服务端收到客户端的请求可能是不完整的,也可能是多个请求连在一起的。

一个示例:

假如使用"\n"作为区分数据边界的标识,有两个请求"ABC\n" 和 "EFG\n"先后发送给服务端,由于TCP分片等机制,服务端获取的数据可能的情况有以下两种:

收到的数据是"AB"即不完整的

对于收到"AB"这种不完整的情况,应该继续等待剩余请求数据到来再处理这个请求(在dealInput中返回1,说明这个请求还要等待一个字节)

收到的数据是"ABC\nEFG\n",多个请求连在一起的。

对于"ABC\nEFG\n"这样的请求,我们需要逐个字节读取(在dealInput中返回1,说明这个请求还要读取一个字节),直到读取到"\n"字符,然后处理这个请求。处理完毕后WorkerMan发现Socket缓冲区还有请求数据没读取,同样逐个字节读取,直到读取到"\n"后处理对应请求。

区分数据边界的标识没有固定的规定,例如可以用单个特殊字符放在请求数据结尾来标记,也可以在请求数据头部放置固定4个字节的pack过的int值来标记数据包长度,还可以用其它的方法。

2、数据格式定义

传输的内容是按照商定的能识别格式传递的。例如定义一个通信协议的数据格式是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个字节,也就是整个请求的数据长度