GatewayProtocol.php 4.3 KB

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