GatewayProtocol.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace GatewayClient;
  3. /**
  4. * This file is part of workerman.
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the MIT-LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @author walkor<walkor@workerman.net>
  11. * @copyright walkor<walkor@workerman.net>
  12. * @link http://www.workerman.net/
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. /**
  16. * Gateway 与 Worker 间通讯的二进制协议
  17. *
  18. * struct GatewayProtocol
  19. * {
  20. * unsigned int pack_len,
  21. * unsigned char cmd,//命令字
  22. * unsigned int local_ip,
  23. * unsigned short local_port,
  24. * unsigned int client_ip,
  25. * unsigned short client_port,
  26. * unsigned int connection_id,
  27. * unsigned char flag,
  28. * unsigned short gateway_port,
  29. * unsigned int ext_len,
  30. * char[ext_len] ext_data,
  31. * char[pack_length-HEAD_LEN] body//包体
  32. * }
  33. * NCNnNnNCnN
  34. */
  35. class GatewayProtocol
  36. {
  37. // 发给worker,gateway有一个新的连接
  38. const CMD_ON_CONNECT = 1;
  39. // 发给worker的,客户端有消息
  40. const CMD_ON_MESSAGE = 3;
  41. // 发给worker上的关闭链接事件
  42. const CMD_ON_CLOSE = 4;
  43. // 发给gateway的向单个用户发送数据
  44. const CMD_SEND_TO_ONE = 5;
  45. // 发给gateway的向所有用户发送数据
  46. const CMD_SEND_TO_ALL = 6;
  47. // 发给gateway的踢出用户
  48. // 1、如果有待发消息,将在发送完后立即销毁用户连接
  49. // 2、如果无待发消息,将立即销毁用户连接
  50. const CMD_KICK = 7;
  51. // 发给gateway的立即销毁用户连接
  52. const CMD_DESTROY = 8;
  53. // 发给gateway,通知用户session更新
  54. const CMD_UPDATE_SESSION = 9;
  55. // 获取在线状态
  56. const CMD_GET_ALL_CLIENT_SESSIONS = 10;
  57. // 判断是否在线
  58. const CMD_IS_ONLINE = 11;
  59. // client_id绑定到uid
  60. const CMD_BIND_UID = 12;
  61. // 解绑
  62. const CMD_UNBIND_UID = 13;
  63. // 向uid发送数据
  64. const CMD_SEND_TO_UID = 14;
  65. // 根据uid获取绑定的clientid
  66. const CMD_GET_CLIENT_ID_BY_UID = 15;
  67. // 批量获取uid列表批量获取绑定的clientid
  68. const CMD_BATCH_GET_CLIENT_ID_BY_UID = 16;
  69. // 加入组
  70. const CMD_JOIN_GROUP = 20;
  71. // 离开组
  72. const CMD_LEAVE_GROUP = 21;
  73. // 向组成员发消息
  74. const CMD_SEND_TO_GROUP = 22;
  75. // 获取组成员
  76. const CMD_GET_CLIENT_SESSIONS_BY_GROUP = 23;
  77. // 获取组在线连接数
  78. const CMD_GET_CLIENT_COUNT_BY_GROUP = 24;
  79. // 按照条件查找
  80. const CMD_SELECT = 25;
  81. // 获取在线的群组ID
  82. const CMD_GET_GROUP_ID_LIST = 26;
  83. // 取消分组
  84. const CMD_UNGROUP = 27;
  85. // worker连接gateway事件
  86. const CMD_WORKER_CONNECT = 200;
  87. // 心跳
  88. const CMD_PING = 201;
  89. // GatewayClient连接gateway事件
  90. const CMD_GATEWAY_CLIENT_CONNECT = 202;
  91. // 根据client_id获取session
  92. const CMD_GET_SESSION_BY_CLIENT_ID = 203;
  93. // 发给gateway,覆盖session
  94. const CMD_SET_SESSION = 204;
  95. // 当websocket握手时触发,只有websocket协议支持此命令字
  96. const CMD_ON_WEBSOCKET_CONNECT = 205;
  97. // 包体是标量
  98. const FLAG_BODY_IS_SCALAR = 0x01;
  99. // 通知gateway在send时不调用协议encode方法,在广播组播时提升性能
  100. const FLAG_NOT_CALL_ENCODE = 0x02;
  101. /**
  102. * 包头长度
  103. *
  104. * @var int
  105. */
  106. const HEAD_LEN = 28;
  107. public static $empty = array(
  108. 'cmd' => 0,
  109. 'local_ip' => 0,
  110. 'local_port' => 0,
  111. 'client_ip' => 0,
  112. 'client_port' => 0,
  113. 'connection_id' => 0,
  114. 'flag' => 0,
  115. 'gateway_port' => 0,
  116. 'ext_data' => '',
  117. 'body' => '',
  118. );
  119. /**
  120. * 返回包长度
  121. *
  122. * @param string $buffer
  123. * @return int return current package length
  124. */
  125. public static function input($buffer)
  126. {
  127. if (strlen($buffer) < self::HEAD_LEN) {
  128. return 0;
  129. }
  130. $data = unpack("Npack_len", $buffer);
  131. return $data['pack_len'];
  132. }
  133. /**
  134. * 获取整个包的 buffer
  135. *
  136. * @param mixed $data
  137. * @return string
  138. */
  139. public static function encode($data)
  140. {
  141. $flag = (int)is_scalar($data['body']);
  142. if (!$flag) {
  143. $data['body'] = serialize($data['body']);
  144. }
  145. $data['flag'] |= $flag;
  146. $ext_len = strlen($data['ext_data']);
  147. $package_len = self::HEAD_LEN + $ext_len + strlen($data['body']);
  148. return pack("NCNnNnNCnN", $package_len,
  149. $data['cmd'], $data['local_ip'],
  150. $data['local_port'], $data['client_ip'],
  151. $data['client_port'], $data['connection_id'],
  152. $data['flag'], $data['gateway_port'],
  153. $ext_len) . $data['ext_data'] . $data['body'];
  154. }
  155. /**
  156. * 从二进制数据转换为数组
  157. *
  158. * @param string $buffer
  159. * @return array
  160. */
  161. public static function decode($buffer)
  162. {
  163. $data = unpack("Npack_len/Ccmd/Nlocal_ip/nlocal_port/Nclient_ip/nclient_port/Nconnection_id/Cflag/ngateway_port/Next_len",
  164. $buffer);
  165. if ($data['ext_len'] > 0) {
  166. $data['ext_data'] = substr($buffer, self::HEAD_LEN, $data['ext_len']);
  167. if ($data['flag'] & self::FLAG_BODY_IS_SCALAR) {
  168. $data['body'] = substr($buffer, self::HEAD_LEN + $data['ext_len']);
  169. } else {
  170. $data['body'] = unserialize(substr($buffer, self::HEAD_LEN + $data['ext_len']));
  171. }
  172. } else {
  173. $data['ext_data'] = '';
  174. if ($data['flag'] & self::FLAG_BODY_IS_SCALAR) {
  175. $data['body'] = substr($buffer, self::HEAD_LEN);
  176. } else {
  177. $data['body'] = unserialize(substr($buffer, self::HEAD_LEN));
  178. }
  179. }
  180. return $data;
  181. }
  182. }