PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Yab/Socket.php

https://github.com/vib94/Framework
PHP | 272 lines | 146 code | 116 blank | 10 comment | 24 complexity | 26d45b848f83873ce5b174c94269fd07 MD5 | raw file
  1. <?php
  2. /**
  3. * Yab Framework
  4. *
  5. * @category Yab
  6. * @package Yab_Socket
  7. * @author Yann BELLUZZI
  8. * @copyright (c) 2010 YBellu
  9. * @license http://www.ybellu.com/yab-framework/license.html
  10. * @link http://www.ybellu.com/yab-framework
  11. */
  12. class Yab_Socket {
  13. private $_socket = null;
  14. private $_address = null;
  15. private $_port = null;
  16. private $_max_clients = 255;
  17. private $_clients = array();
  18. private $_client = null;
  19. public function __construct($address, $port, $socket = null) {
  20. $this->_address = (string) $address;
  21. $this->_port = (int) $port;
  22. if($socket) {
  23. $this->_socket = $socket;
  24. $this->_client = true;
  25. } else {
  26. $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  27. }
  28. }
  29. public function getAddress() {
  30. return $this->_address;
  31. }
  32. public function getPort() {
  33. return $this->_port;
  34. }
  35. public function read() {
  36. $this->_connect();
  37. if($this->_client !== true)
  38. throw new Yab_Exception('can not write on a server socket');
  39. $stream = @socket_read($this->_socket, 4096);
  40. if($stream === false)
  41. throw new Yab_Exception('can not read on socket, '.$this->error());
  42. return (string) $stream;
  43. }
  44. public function write($stream) {
  45. $this->_connect();
  46. if($this->_client !== true)
  47. throw new Yab_Exception('can not write on a server socket');
  48. $stream = (string) $stream;
  49. $length = strlen($stream);
  50. $written = @socket_write($this->_socket, $stream, $length);
  51. if($written < $length)
  52. throw new Yab_Exception('can not fully write on socket, '.$this->error());
  53. return $this;
  54. }
  55. public function broadcast($stream) {
  56. if($this->_client !== false)
  57. throw new Yab_Exception('can not broadcast on a client socket');
  58. foreach($this->_clients as $key => $client) {
  59. try {
  60. $client->write($stream);
  61. } catch(Yab_Exception $e) {
  62. $this->remClient($key)->_onDisconnect($key);
  63. }
  64. }
  65. return $this;
  66. }
  67. public function listen($max_clients = null) {
  68. if($this->_client)
  69. throw new Yab_Exception('can not listen on a client socket');
  70. $this->_client = false;
  71. if(is_numeric($max_clients))
  72. $this->_max_clients = $max_clients;
  73. if(!socket_bind($this->_socket, $this->_address, $this->_port))
  74. throw new Yab_Exception('can not bind socket to "'.$this->_address.':'.$this->_port.'" '.$this->error());
  75. if(!socket_listen($this->_socket))
  76. throw new Yab_Exception('can not listen socket '.$this->error());
  77. while(true) {
  78. $client = socket_accept($this->_socket);
  79. $address = null;
  80. $port = null;
  81. socket_getpeername($client, $address, $port);
  82. $socket = new self($address, $port, $client);
  83. $this->_onAccept($socket);
  84. }
  85. }
  86. public function addClient($key, Yab_Socket $client) {
  87. if($this->_client !== false)
  88. throw new Yab_Exception('can not add client on a client socket');
  89. if($this->hasClient($key))
  90. throw new Yab_Exception('can not add this client because it is already added with this identity "'.$key.'"');
  91. if($this->_max_clients <= count($this->_clients))
  92. throw new Yab_Exception('can not add more clients because the limit of "'.$this->_max_clients.'" is reached');
  93. $this->_clients[$key] = $client;
  94. return $this;
  95. }
  96. public function remClient($key) {
  97. if($this->_client !== false)
  98. throw new Yab_Exception('can not remove client on a client socket');
  99. if(!$this->hasClient($key))
  100. throw new Yab_Exception('can not remove this client because the identity "'.$key.'" does not exists');
  101. unset($this->_clients[$key]);
  102. return $this;
  103. }
  104. public function getClient($key) {
  105. if($this->_client !== false)
  106. throw new Yab_Exception('can not get client on a client socket');
  107. if(!$this->hasClient($key))
  108. throw new Yab_Exception('there is no client identified by "'.$key.'"');
  109. return $this->_clients[$key];
  110. }
  111. public function hasClient($key) {
  112. if($this->_client !== false)
  113. throw new Yab_Exception('can not have client on a client socket');
  114. return array_key_exists($key, $this->_clients);
  115. }
  116. public function stop() {
  117. if($this->_client !== false)
  118. throw new Yab_Exception('can not stop a client socket');
  119. $this->_onStop();
  120. return $this->_close();
  121. }
  122. public function error() {
  123. $int = socket_last_error($this->_socket);
  124. $str = socket_strerror($int);
  125. return 'ERROR['.$int.'] '.$str;
  126. }
  127. private function _connect() {
  128. if($this->_client !== null)
  129. return $this;
  130. $this->_client = true;
  131. if(!socket_bind($this->_socket, $this->_address))
  132. throw new Yab_Exception('can not bind socket to "'.$this->_address.'" '.$this->error());
  133. if(!socket_connect($this->_socket, $this->_address, $this->_port))
  134. throw new Yab_Exception('can not connect socket to "'.$this->_address.':'.$this->_port.'" '.$this->error());
  135. $this->_onConnect();
  136. return $this;
  137. }
  138. private function _close() {
  139. if(!is_resource($this->_socket))
  140. return $this;
  141. socket_close($this->_socket);
  142. return $this;
  143. }
  144. public function __destruct() {
  145. try {
  146. $this->stop();
  147. } catch(Yab_Exception $e) {
  148. $this->_close();
  149. }
  150. return $this;
  151. }
  152. protected function _onAccept(Yab_Socket $client) {}
  153. protected function _onConnect() {}
  154. protected function _onDisconnect($key) {}
  155. protected function _onStop() {}
  156. }