PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/examples/PHP/peering2.php

https://github.com/plouj/zguide
PHP | 202 lines | 141 code | 28 blank | 33 comment | 28 complexity | 34012d90dc289fe14398f1490bc459ab MD5 | raw file
  1. <?php
  2. /*
  3. * Broker peering simulation (part 2)
  4. * Prototypes the request-reply flow
  5. * @author Ian Barber <ian(dot)barber(at)gmail(dot)com>
  6. */
  7. include "zmsg.php";
  8. define("NBR_CLIENTS", 10);
  9. define("NBR_WORKERS", 3);
  10. // Request-reply client using REQ socket
  11. function client_thread($self) {
  12. $context = new ZMQContext();
  13. $client = new ZMQSocket($context, ZMQ::SOCKET_REQ);
  14. $endpoint = sprintf("ipc://%s-localfe.ipc", $self);
  15. $client->connect($endpoint);
  16. while(true) {
  17. // Send request, get reply
  18. $client->send("HELLO");
  19. $reply = $client->recv();
  20. printf("I: client status: %s%s", $reply, PHP_EOL);
  21. }
  22. }
  23. // Worker using REQ socket to do LRU routing
  24. function worker_thread ($self) {
  25. $context = new ZMQContext();
  26. $worker = $context->getSocket(ZMQ::SOCKET_REQ);
  27. $endpoint = sprintf("ipc://%s-localbe.ipc", $self);
  28. $worker->connect($endpoint);
  29. // Tell broker we're ready for work
  30. $worker->send("READY");
  31. while(true) {
  32. $zmsg = new Zmsg($worker);
  33. $zmsg->recv();
  34. sleep(1);
  35. $zmsg->body_fmt("OK - %04x", mt_rand(0, 0x10000));
  36. $zmsg->send();
  37. }
  38. }
  39. // First argument is this broker's name
  40. // Other arguments are our peers' names
  41. if($_SERVER['argc'] < 2) {
  42. echo "syntax: peering2 me {you}...", PHP_EOL;
  43. exit();
  44. }
  45. $self = $_SERVER['argv'][1];
  46. for($client_nbr = 0; $client_nbr < NBR_CLIENTS; $client_nbr++) {
  47. $pid = pcntl_fork();
  48. if($pid == 0) {
  49. client_thread($self);
  50. return;
  51. }
  52. }
  53. for($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) {
  54. $pid = pcntl_fork();
  55. if($pid == 0) {
  56. worker_thread($self);
  57. return;
  58. }
  59. }
  60. printf ("I: preparing broker at %s... %s", $self, PHP_EOL);
  61. // Prepare our context and sockets
  62. $context = new ZMQContext();
  63. // Bind cloud frontend to endpoint
  64. $cloudfe = $context->getSocket(ZMQ::SOCKET_XREP);
  65. $endpoint = sprintf("ipc://%s-cloud.ipc", $self);
  66. $cloudfe->setSockOpt(ZMQ::SOCKOPT_IDENTITY, $self);
  67. $cloudfe->bind($endpoint);
  68. // Connect cloud backend to all peers
  69. $cloudbe = $context->getSocket(ZMQ::SOCKET_XREP);
  70. $cloudbe->setSockOpt(ZMQ::SOCKOPT_IDENTITY, $self);
  71. for ($argn = 2; $argn < $_SERVER['argc']; $argn++) {
  72. $peer = $_SERVER['argv'][$argn];
  73. printf ("I: connecting to cloud backend at '%s'%s", $peer, PHP_EOL);
  74. $endpoint = sprintf("ipc://%s-cloud.ipc", $peer);
  75. $cloudbe->connect($endpoint);
  76. }
  77. // Prepare local frontend and backend
  78. $localfe = new ZMQSocket($context, ZMQ::SOCKET_XREP);
  79. $endpoint = sprintf("ipc://%s-localfe.ipc", $self);
  80. $localfe->bind($endpoint);
  81. $localbe = new ZMQSocket($context, ZMQ::SOCKET_XREP);
  82. $endpoint = sprintf("ipc://%s-localbe.ipc", $self);
  83. $localbe->bind($endpoint);
  84. // Get user to tell us when we can start...
  85. printf ("Press Enter when all brokers are started: ");
  86. $fp = fopen('php://stdin', 'r');
  87. $line = fgets($fp, 512);
  88. fclose($fp);
  89. // Interesting part
  90. // -------------------------------------------------------------
  91. // Request-reply flow
  92. // - Poll backends and process local/cloud replies
  93. // - While worker available, route localfe to local or cloud
  94. // Queue of available workers
  95. $capacity = 0;
  96. $worker_queue = array();
  97. $readable = $writeable = array();
  98. while(true) {
  99. $poll = new ZMQPoll();
  100. $poll->add($localbe, ZMQ::POLL_IN);
  101. $poll->add($cloudbe, ZMQ::POLL_IN);
  102. $events = 0;
  103. // If we have no workers anyhow, wait indefinitely
  104. try {
  105. $events = $poll->poll($readable, $writeable, $capacity ? 1000000 : -1);
  106. } catch(ZMQPollException $e) {
  107. break;
  108. }
  109. if($events > 0) {
  110. foreach($readable as $socket) {
  111. $zmsg = new Zmsg($socket);
  112. // Handle reply from local worker
  113. if($socket === $localbe) {
  114. $zmsg->recv();
  115. // Use worker address for LRU routing
  116. $worker_queue[] = $zmsg->unwrap();
  117. $capacity++;
  118. if($zmsg->address() == "READY") {
  119. continue;
  120. }
  121. }
  122. // Or handle reply from peer broker
  123. else if($socket === $cloudbe) {
  124. // We don't use peer broker address for anything
  125. $zmsg->recv()->unwrap();
  126. }
  127. // Route reply to cloud if it's addressed to a broker
  128. for($argn = 2; $argn < $_SERVER['argc']; $argn++) {
  129. if($zmsg->address() == $_SERVER['argv'][$argn]) {
  130. $zmsg->set_socket($cloudfe)->send();
  131. $zmsg = null;
  132. }
  133. }
  134. // Route reply to client if we still need to
  135. if($zmsg) {
  136. $zmsg->set_socket($localfe)->send();
  137. }
  138. }
  139. }
  140. // Now route as many clients requests as we can handle
  141. while($capacity) {
  142. $poll = new ZMQPoll();
  143. $poll->add($localfe, ZMQ::POLL_IN);
  144. $poll->add($cloudfe, ZMQ::POLL_IN);
  145. $reroutable = false;
  146. $events = $poll->poll($readable, $writeable, 0);
  147. if($events > 0) {
  148. foreach($readable as $socket) {
  149. $zmsg = new Zmsg($socket);
  150. $zmsg->recv();
  151. // We'll do peer brokers first, to prevent starvation
  152. if($socket === $cloudfe) {
  153. $reroutable = false;
  154. }
  155. else if($socket === $localfe) {
  156. $reroutable = true;
  157. }
  158. // If reroutable, send to cloud 20% of the time
  159. // Here we'd normally use cloud status information
  160. if($reroutable && $_SERVER['argc'] > 2 && mt_rand(0, 4) == 0) {
  161. $zmsg->wrap($_SERVER['argv'][mt_rand(2, ($_SERVER['argc']-1))]);
  162. $zmsg->set_socket($cloudbe)->send();
  163. }
  164. else {
  165. $zmsg->wrap(array_shift($worker_queue), "");
  166. $zmsg->set_socket($localbe)->send();
  167. $capacity--;
  168. }
  169. }
  170. } else {
  171. break; // No work, go back to backends
  172. }
  173. }
  174. }