/rbtree_with_stats/client.php

http://dutils.googlecode.com/ · PHP · 208 lines · 199 code · 8 blank · 1 comment · 2 complexity · 154ec562cec7540893d65077b4d950fe MD5 · raw file

  1. <?php
  2. class PacketType {
  3. const Ping = 0;
  4. const ListItems = 1;
  5. const SetUser = 2;
  6. const LocateUserPosition = 3;
  7. const SetUsers = 4;
  8. static public function toString($v) {
  9. static $lookup;
  10. if (!isset($lookup)) {
  11. $class = new ReflectionClass(__CLASS__);
  12. $lookup = array_flip($class->getConstants());
  13. }
  14. return $lookup[$v];
  15. }
  16. }
  17. class Packet {
  18. public $type;
  19. public $typeString;
  20. public $data;
  21. public function __construct($type, $data) {
  22. $this->type = $type;
  23. $this->typeString = PacketType::toString($type);
  24. $this->data = $data;
  25. //echo PacketType::toString($this->type) . "\n";
  26. }
  27. }
  28. class SocketClient {
  29. public $f;
  30. public function __construct() {
  31. }
  32. public function connect($ip, $port) {
  33. $this->f = fsockopen($ip, $port);
  34. if (!$this->f) throw(new Exception("Can't connect to {$ip}:{$port}"));
  35. }
  36. public function close() {
  37. fclose($this->f);
  38. $this->f = null;
  39. }
  40. public function sendPacket($type, $data = '') {
  41. $start = microtime(true);
  42. {
  43. fwrite($this->f, pack('v', strlen($data)));
  44. fwrite($this->f, pack('c', $type));
  45. fwrite($this->f, $data);
  46. $response = $this->recvPacket();
  47. }
  48. $end = microtime(true);
  49. //printf("%.6f\n", $end - $start);
  50. return $response;
  51. }
  52. public function ping() {
  53. return $this->sendPacket(PacketType::Ping);
  54. }
  55. //const MAX_SET_USERS = 4000; // pow(2, 16) / (4 * 4)
  56. //const MAX_SET_USERS = 4096; // pow(2, 16) / (4 * 4)
  57. const MAX_SET_USERS = 4095; // pow(2, 16) / (4 * 4)
  58. protected $setUsers = array();
  59. public function setUser($userId, $scoreIndex, $scoreTimestamp, $scoreValue) {
  60. $result = $this->sendPacket(
  61. PacketType::SetUser,
  62. pack('V*', $userId, $scoreIndex, $scoreTimestamp, $scoreValue)
  63. );
  64. //print_r($result);
  65. return $result;
  66. }
  67. public function setUsers($infos) {
  68. assert(count($this->setUsers) <= self::MAX_SET_USERS);
  69. $data = '';
  70. foreach ($infos as $info) {
  71. //$data .= pack('V*', $userId, $scoreIndex, $scoreTimestamp, $scoreValue);
  72. $data .= pack('V*', $info[0], $info[1], $info[2], $info[3]);
  73. //if (strlen($data) > )
  74. }
  75. $result = $this->sendPacket(PacketType::SetUsers, $data);
  76. }
  77. public function setUserBuffer($userId, $scoreIndex, $scoreTimestamp, $scoreValue) {
  78. $this->setUsers[] = array($userId, $scoreIndex, $scoreTimestamp, $scoreValue);
  79. if (count($this->setUsers) >= self::MAX_SET_USERS) {
  80. $this->setUserBufferFlush();
  81. }
  82. static $shutdown_callback;
  83. if (!isset($shutdown_callback)) {
  84. $shutdown_callback = true;
  85. register_shutdown_function(array($this, 'setUserBufferFlush'));
  86. }
  87. }
  88. public function setUserBufferFlush() {
  89. if (empty($this->setUsers)) return;
  90. $start = microtime(true);
  91. {
  92. if (true) {
  93. $this->setUsers($this->setUsers);
  94. } else {
  95. foreach ($this->setUsers as $user) {
  96. call_user_func_array(array($this, 'setUser'), $user);
  97. }
  98. }
  99. $this->setUsers = array();
  100. }
  101. $end = microtime(true);
  102. //printf("%.6f\n", $end - $start);
  103. }
  104. public function locateUserPosition($userId, $scoreIndex) {
  105. $this->setUserBufferFlush();
  106. $result = $this->sendPacket(
  107. PacketType::LocateUserPosition,
  108. pack('V*', $userId, $scoreIndex)
  109. );
  110. //print_r($result); return $result;
  111. list(,$position) = unpack('V', $result->data);
  112. return $position;
  113. }
  114. public function listItems($scoreIndex, $offset, $count) {
  115. $this->setUserBufferFlush();
  116. $result = $this->sendPacket(
  117. PacketType::ListItems,
  118. pack('V*', $scoreIndex, $offset, $count)
  119. );
  120. //print_r($result); return $result;
  121. $entries = array();
  122. $data = $result->data;
  123. while (strlen($data)) {
  124. $entry = array_combine(array('position', 'userId', 'score', 'timestamp'), array_values(unpack('V4', $data)));
  125. $data = substr($data, 4 * 4);
  126. $entries[] = $entry;
  127. }
  128. return $entries;
  129. }
  130. public function recvPacket() {
  131. //echo "[@0:.]";
  132. list(,$packetSize) = unpack('v', $v = fread($this->f, 2));
  133. if (strlen($v) < 2) throw(new Exception("Error receiving a packet"));
  134. //echo "[@1:{$packetSize}]";
  135. list(,$packetType) = unpack('c', fread($this->f, 1));
  136. //echo "[@2:{$packetType}]";
  137. $packetData = ($packetSize > 0) ? fread($this->f, $packetSize) : '';
  138. //echo "[@3:{$packetData}]";
  139. return new Packet($packetType, $packetData);
  140. }
  141. }
  142. $socketClient = new SocketClient();
  143. $socketClient->connect('127.0.0.1', 9777);
  144. $time = time();
  145. for ($n = 0; $n < 100000; $n++) {
  146. //for ($n = 0; $n < 1000; $n++) {
  147. //for ($n = 0; $n < 100; $n++) {
  148. //for ($n = 0; $n < 20; $n++) {
  149. $socketClient->setUserBuffer(mt_rand(0, 100000), 0, $time + mt_rand(-50, 4), mt_rand(0, 500));
  150. }
  151. $socketClient->setUserBuffer(1000, 0, $time, 200);
  152. $socketClient->setUserBuffer(1001, 0, $time, 300);
  153. $socketClient->setUserBuffer(1000, 0, $time + 1, 300);
  154. //$socketClient->setUserBufferFlush();
  155. printf("Position(1000):%d\n", $pos_1000 = $socketClient->locateUserPosition(1000, 0));
  156. printf("Position(1001):%d\n", $pos_1001 = $socketClient->locateUserPosition(1001, 0));
  157. print_r($socketClient->listItems(0, $pos_1000, 3));
  158. print_r($socketClient->listItems(0, 0, 3));
  159. //print_r($socketClient->listItems(0, 20, 20));
  160. /*
  161. while (true) {
  162. //echo "[1]";
  163. $socketClient->sendPacket(PacketType::Ping);
  164. //echo "[2]";
  165. $socketClient->recvPacket();
  166. //echo "[3]";
  167. //$socketClient->sendPacket(PacketType::Ping);
  168. //$socketClient->recvPacket();
  169. }
  170. */