Buffer.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. namespace WORKERMAN\Protocols;
  3. /**
  4. * 通用的server协议,二进制协议
  5. *
  6. * struct JMProtocol
  7. * {
  8. * unsigned char version,//版本
  9. * unsigned short series_id,//序列号 udp协议使用
  10. * unsigned short cmd,//主命令字
  11. * unsigned short sub_cmd,//子命令字
  12. * int code,//返回码
  13. * unsigned int pack_len,//包长
  14. * char[pack_length] body//包体
  15. * }
  16. *
  17. * @author walkor <worker-man@qq.com>
  18. */
  19. class Buffer
  20. {
  21. /**
  22. * 版本
  23. * @var integer
  24. */
  25. const VERSION = 0x01;
  26. /**
  27. * 包头长度
  28. * @var integer
  29. */
  30. const HEAD_LEN = 15;
  31. /**
  32. * 默认包体序列化类型
  33. * @var integer
  34. */
  35. const DEFAULT_SERIALIZE_TYPE = 0;
  36. /**
  37. * 序列号,防止串包
  38. * @var integer
  39. */
  40. protected static $seriesId = 0;
  41. /**
  42. * 协议头
  43. * @var array
  44. */
  45. public $header = array(
  46. 'version' => self::VERSION,
  47. 'series_id' => 0,
  48. 'cmd' => 0,
  49. 'sub_cmd' => 0,
  50. 'code' => 0,
  51. 'pack_len' => self::HEAD_LEN
  52. );
  53. /**
  54. * 包体
  55. * @var string
  56. */
  57. public $body = '';
  58. /**
  59. * 初始化
  60. * @return void
  61. */
  62. public function __construct($buffer = null)
  63. {
  64. if($buffer)
  65. {
  66. $data = self::bufferToData($buffer);
  67. $this->body = $data['body'];
  68. unset($data['body']);
  69. $this->header = $data;
  70. }
  71. else
  72. {
  73. if(self::$seriesId>=65535)
  74. {
  75. self::$seriesId = 0;
  76. }
  77. else
  78. {
  79. $this->header['series_id'] = self::$seriesId++;
  80. }
  81. }
  82. }
  83. /**
  84. * 判断数据包是否都到了
  85. * @param string $bin
  86. * @return int int=0数据是完整的 int>1数据不完整,还要继续接收int字节
  87. */
  88. public static function input($bin)
  89. {
  90. $len = strlen($bin);
  91. if($len < self::HEAD_LEN)
  92. {
  93. return self::HEAD_LEN - $len;
  94. }
  95. $unpack_data = unpack("Cversion/Sseries_id/Scmd/Ssub_cmd/icode/Ipack_len", $bin);
  96. if($unpack_data['pack_len'] > $len)
  97. {
  98. return $unpack_data['pack_len'] - $len;
  99. }
  100. return 0;
  101. }
  102. /**
  103. * 设置包体
  104. * @param string $body_str
  105. * @return void
  106. */
  107. public function setBody($body_str)
  108. {
  109. $this->body = (string) $body_str;
  110. }
  111. /**
  112. * 获取整个包的buffer
  113. * @param string $data
  114. * @return string
  115. */
  116. public function getBuffer()
  117. {
  118. $this->header['pack_len'] = self::HEAD_LEN + strlen($this->body);
  119. return pack("CSSSiI", $this->header['version'], $this->header['series_id'], $this->header['cmd'], $this->header['sub_cmd'], $this->header['code'], $this->header['pack_len']).$this->body;
  120. }
  121. /**
  122. * 从二进制数据转换为数组
  123. * @param string $bin
  124. * @return array
  125. */
  126. public static function decode($buffer)
  127. {
  128. $data = unpack("Cversion/Sseries_id/Scmd/Ssub_cmd/icode/Ipack_len", $buffer);
  129. $data['body'] = '';
  130. $body_len = $data['pack_len'] - self::HEAD_LEN;
  131. if($body_len > 0)
  132. {
  133. $data['body'] = substr($buffer, self::HEAD_LEN, $body_len);
  134. }
  135. return $data;
  136. }
  137. }