Buffer.php 3.8 KB

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