PageRenderTime 20ms CodeModel.GetById 2ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

/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
 13class Yab_Socket {
 14
 15	private $_socket = null;
 16
 17	private $_address = null;
 18	private $_port = null;
 19
 20	private $_max_clients = 255;
 21	private $_clients = array();
 22
 23	private $_client = null;
 24
 25	public function __construct($address, $port, $socket = null) {
 26	
 27		$this->_address = (string) $address;
 28		$this->_port = (int) $port;
 29		
 30		if($socket) {
 31		
 32			$this->_socket = $socket;
 33			
 34			$this->_client = true;
 35			
 36		} else {
 37			
 38			$this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
 39			
 40		}
 41
 42	}
 43
 44	public function getAddress() {
 45	
 46		return $this->_address;
 47	
 48	}
 49
 50	public function getPort() {
 51	
 52		return $this->_port;
 53	
 54	}
 55
 56	public function read() {
 57	
 58		$this->_connect();
 59
 60		if($this->_client !== true)
 61			throw new Yab_Exception('can not write on a server socket');
 62	
 63		$stream = @socket_read($this->_socket, 4096);
 64	
 65		if($stream === false)
 66			throw new Yab_Exception('can not read on socket,  '.$this->error());
 67		
 68		return (string) $stream;
 69	
 70	}	
 71
 72	public function write($stream) {
 73	
 74		$this->_connect();
 75
 76		if($this->_client !== true)
 77			throw new Yab_Exception('can not write on a server socket');
 78		
 79		$stream = (string) $stream;
 80
 81		$length = strlen($stream);
 82		
 83		$written = @socket_write($this->_socket, $stream, $length);
 84		
 85		if($written < $length)
 86			throw new Yab_Exception('can not fully write on socket, '.$this->error());
 87
 88		return $this;
 89
 90	}
 91
 92	public function broadcast($stream) {
 93	
 94		if($this->_client !== false)
 95			throw new Yab_Exception('can not broadcast on a client socket');
 96
 97		foreach($this->_clients as $key => $client) {
 98		
 99			try {
100		
101				$client->write($stream);
102				
103			} catch(Yab_Exception $e) {
104			
105				$this->remClient($key)->_onDisconnect($key);
106			
107			}
108			
109		}
110		
111		return $this;
112	
113	}
114
115	public function listen($max_clients = null) {
116	
117		if($this->_client)
118			throw new Yab_Exception('can not listen on a client socket');
119
120		$this->_client = false;
121			
122		if(is_numeric($max_clients))
123			$this->_max_clients = $max_clients;
124			
125		if(!socket_bind($this->_socket, $this->_address, $this->_port))
126			throw new Yab_Exception('can not bind socket to "'.$this->_address.':'.$this->_port.'" '.$this->error());
127		
128		if(!socket_listen($this->_socket))
129			throw new Yab_Exception('can not listen socket '.$this->error());
130		
131		while(true) {
132		
133			$client = socket_accept($this->_socket);
134
135			$address = null;
136			$port = null;
137			
138			socket_getpeername($client, $address, $port);
139
140			$socket = new self($address, $port, $client);
141
142			$this->_onAccept($socket);
143			
144		}
145	
146	}
147
148	public function addClient($key, Yab_Socket $client) {
149	
150		if($this->_client !== false)
151			throw new Yab_Exception('can not add client on a client socket');
152
153		if($this->hasClient($key))
154			throw new Yab_Exception('can not add this client because it is already added with this identity "'.$key.'"');
155		
156		if($this->_max_clients <= count($this->_clients))
157			throw new Yab_Exception('can not add more clients because the limit of "'.$this->_max_clients.'" is reached');
158
159		$this->_clients[$key] = $client;
160		
161		return $this;
162	
163	}
164
165	public function remClient($key) {
166	
167		if($this->_client !== false)
168			throw new Yab_Exception('can not remove client on a client socket');
169
170		if(!$this->hasClient($key))
171			throw new Yab_Exception('can not remove this client because the identity "'.$key.'" does not exists');
172
173		unset($this->_clients[$key]);
174		
175		return $this;
176	
177	}
178
179	public function getClient($key) {
180	
181		if($this->_client !== false)
182			throw new Yab_Exception('can not get client on a client socket');
183
184		if(!$this->hasClient($key))
185			throw new Yab_Exception('there is no client identified by "'.$key.'"');
186			
187		return $this->_clients[$key];
188	
189	}
190
191	public function hasClient($key) {
192	
193		if($this->_client !== false)
194			throw new Yab_Exception('can not have client on a client socket');
195
196		return array_key_exists($key, $this->_clients);
197	
198	}
199
200	public function stop() {
201	
202		if($this->_client !== false)
203			throw new Yab_Exception('can not stop a client socket');
204
205		$this->_onStop();
206		
207		return $this->_close();
208	
209	}
210
211	public function error() {
212	
213		$int = socket_last_error($this->_socket);
214		
215		$str = socket_strerror($int);
216		
217		return 'ERROR['.$int.'] '.$str;
218	
219	}
220
221	private function _connect() {
222		
223		if($this->_client !== null)
224			return $this;
225	
226		$this->_client = true;
227			
228		if(!socket_bind($this->_socket, $this->_address))
229			throw new Yab_Exception('can not bind socket to "'.$this->_address.'" '.$this->error());
230		
231		if(!socket_connect($this->_socket, $this->_address, $this->_port))
232			throw new Yab_Exception('can not connect socket to "'.$this->_address.':'.$this->_port.'" '.$this->error());
233		
234		$this->_onConnect();
235		
236		return $this;
237	
238	}
239	
240	private function _close() {
241		
242		if(!is_resource($this->_socket))
243			return $this;
244			
245		socket_close($this->_socket);
246		
247		return $this;
248	
249	}
250	
251	public function __destruct() {
252
253		try {
254		
255			$this->stop();
256			
257		} catch(Yab_Exception $e) {
258	
259			$this->_close();
260		
261		}
262		
263		return $this;
264
265	}
266	
267	protected function _onAccept(Yab_Socket $client) {}
268	protected function _onConnect() {}
269	protected function _onDisconnect($key) {}
270	protected function _onStop() {}
271		
272}