GatewayProtocol.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace Protocols;
  3. /**
  4. * Gateway与Worker间通讯的二进制协议
  5. *
  6. * struct GatewayProtocol
  7. * {
  8. * unsigned int pack_len,
  9. * unsigned char cmd,//命令字
  10. * unsigned int local_ip,
  11. * unsigned short local_port,
  12. * unsigned int socket_id,
  13. * unsigned int client_ip,
  14. * unsigned short client_port,
  15. * unsigned int uid,
  16. * unsigned int ext_len,
  17. * char[ext_len] ext_data,
  18. * char[pack_length-HEAD_LEN] body//包体
  19. * }
  20. *
  21. *
  22. * @author walkor <workerman.net>
  23. */
  24. class GatewayProtocol
  25. {
  26. // 发给worker,gateway有一个新的连接
  27. const CMD_ON_GATEWAY_CONNECTION = 1;
  28. // 发给worker的未绑定socket上有消息事件
  29. const CMD_ON_CONNECTION = 2;
  30. // 发给worker的绑定socket上有消息事件
  31. const CMD_ON_MESSAGE = 3;
  32. // 发给worker上的关闭链接事件
  33. const CMD_ON_CLOSE = 4;
  34. // 发给gateway的向单个用户发送数据
  35. const CMD_SEND_TO_ONE = 5;
  36. // 发给gateway的向所有用户发送数据
  37. const CMD_SEND_TO_ALL = 6;
  38. // 发给gateway的踢出用户
  39. const CMD_KICK = 7;
  40. // 发给gateway的通知用户(通过验证)链接成功,绑定uid gid socketid
  41. const CMD_CONNECT_SUCCESS = 8;
  42. // 发给gateway,通知用户session更改
  43. const CMD_UPDATE_SESSION = 9;
  44. // 获取在线状态
  45. const CMD_GET_ONLINE_STATUS = 10;
  46. // 判断是否在线
  47. const CMD_IS_ONLINE = 11;
  48. /**
  49. * 包头长度
  50. * @var integer
  51. */
  52. const HEAD_LEN = 29;
  53. /**
  54. * 协议头
  55. * @var array
  56. */
  57. public $header = array(
  58. 'pack_len' => self::HEAD_LEN,
  59. 'cmd' => 0,
  60. 'local_ip' => '',
  61. 'local_port' => 0,
  62. 'socket_id' => 0,
  63. 'client_ip' => '',
  64. 'client_port' => 0,
  65. 'uid' => 0,
  66. 'ext_len' => 0,
  67. );
  68. /**
  69. * 扩展数据,
  70. * gateway发往worker时这里存储的是session字符串
  71. * worker发往gateway时,并且CMD_UPDATE_SESSION时存储的是session字符串
  72. * worker发往gateway时,并且CMD_SEND_TO_ALL时存储的是接收的uid序列,可能是空(代表向所有人发)
  73. * @var string
  74. */
  75. public $ext_data = '';
  76. /**
  77. * 包体
  78. * @var string
  79. */
  80. public $body = '';
  81. /**
  82. * 初始化
  83. * @return void
  84. */
  85. public function __construct($buffer = null)
  86. {
  87. if($buffer)
  88. {
  89. $data = self::decode($buffer);
  90. $this->ext_data = $data['ext_data'];
  91. $this->body = $data['body'];
  92. unset($data['ext_data'], $data['body']);
  93. $this->header = $data;
  94. }
  95. }
  96. /**
  97. * 判断数据包是否都到了
  98. * @param string $buffer
  99. * @return int int=0数据是完整的 int>0数据不完整,还要继续接收int字节
  100. */
  101. public static function input($buffer)
  102. {
  103. $len = strlen($buffer);
  104. // 至少需要四字节才能解出包的长度
  105. if($len < 4)
  106. {
  107. return 4 - $len;
  108. }
  109. $data = unpack("Npack_len", $buffer);
  110. return $data['pack_len'] - $len;
  111. }
  112. /**
  113. * 获取整个包的buffer
  114. * @param string $data
  115. * @return string
  116. */
  117. public function getBuffer()
  118. {
  119. $this->header['ext_len'] = strlen($this->ext_data);
  120. $this->header['pack_len'] = self::HEAD_LEN + $this->header['ext_len'] + strlen($this->body);
  121. return pack("NCNnNNnNN", $this->header['pack_len'],
  122. $this->header['cmd'], ip2long($this->header['local_ip']),
  123. $this->header['local_port'], $this->header['socket_id'],
  124. ip2long($this->header['client_ip']), $this->header['client_port'],
  125. $this->header['uid'],
  126. $this->header['ext_len']) . $this->ext_data . $this->body;
  127. }
  128. /**
  129. * 从二进制数据转换为数组
  130. * @param string $buffer
  131. * @return array
  132. */
  133. protected static function decode($buffer)
  134. {
  135. $data = unpack("Npack_len/Ccmd/Nlocal_ip/nlocal_port/Nsocket_id/Nclient_ip/nclient_port/Nuid/Next_len", $buffer);
  136. $data['local_ip'] = long2ip($data['local_ip']);
  137. $data['client_ip'] = long2ip($data['client_ip']);
  138. if($data['ext_len'] > 0)
  139. {
  140. $data['ext_data'] = substr($buffer, self::HEAD_LEN, $data['ext_len']);
  141. $data['body'] = substr($buffer, self::HEAD_LEN + $data['ext_len']);
  142. }
  143. else
  144. {
  145. $data['ext_data'] = '';
  146. $data['body'] = substr($buffer, self::HEAD_LEN);
  147. }
  148. return $data;
  149. }
  150. }