Location: PHPKode > scripts > Client and Server Socket > client-and-server-socket/Socket.php
<?php
/******************************************************************************************************
	LICENSE

	Copyright (C) 2006 Juan M. Hidalgo

    This program is free software; you can redistribute it and/or modify it under the terms of the
    GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
    or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU General Public License for more details.

    You should have received a copy of the GNU General
    Public License along with this program; if not,
    write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
    Boston, MA 02111-1307 USA
****************************************************************************************************/

require_once("AbstractSocket.php");

/**
 * Client Socket to comunication with servers
 *
 * @author		Juan M. Hidalgo
 * @author		Gustavo Gomes
 * @version		0.9
 * @copyright	2006-12-27
 */
class Socket extends AbstractSocket {
	
	const READER_BUFFER = 4096;
	
	/**
	 * Remote Socket Address representation
	 * @var InetSocketAddress
	 */
	protected $remoteAddr = null;
	
	/**
	 * Socket buffer
	 * @var string
	 */
	private $sBuffer;

	/**
	 * Read TimeOut (seconds)
	 * @var int
	 */
	private $iReadTimeOut = 2;

	/**
	 * Write TimeOut (seconds)
	 * @var int
	 */
	private $iWriteTimeOut = 2;

	/**
	 * Constructor - create socket handler, set all parameters
	 * and open socket connection.
	 *
	 * @param	mixed $addr
	 * @param	mixed $port
	 * @param	int $family - (AF_INET|AF_INET6|AF_UNIX)
	 * @param	int $type - (SOCK_DGRAM | SOCK_RAW |	SOCK_RDM | SOCK_SEQPACKET | SOCK_STREAM)
	 * @param	int $protocol - (SOL_SOCKET | SOL_TCP | SOL_UDP)
	 * @throws	SocketException, UnknownHostException
	 */
	public function __construct($addr=null,$port=null,$family=AF_INET,$type=SOCK_STREAM ,$protocol=SOL_TCP) {
		parent::__construct($family, $type, $protocol);
		$this->sBuffer = false;

		if ($addr != null && $port != null)
			$this->open($addr, $port);
	}
	
	/**
	 * Get client address
	 * 
	 * @return	InetAddress
	 */
	public function getLocalAddress() {
		if ($this->socketAddr != null)
			return $this->socketAddr->getAddress();
		return null;
	}

	/**
	 * Get client port
	 * 
	 * @return	int
	 */
	public function getLocalPort(){
		if ($this->socketAddr != null)
			return $this->socketAddr->getPort();
		return null;
	}
	
	/**
	 * Get remote address
	 * 
	 * @return	InetAddress
	 */
	public function getInetAddress() {
		if ($this->remoteAddr != null)
			return $this->remoteAddr->getAddress();
		return null;
	}

	/**
	 * Get remote port
	 * 
	 * @return	int
	 */
	public function getPort(){
		if ($this->remoteAddr != null)
			return $this->remoteAddr->getPort();
		return null;
	}
	
	/**
	 * Get remote socket informations
	 * 
	 * @return	InetSocketAddress
	 */
	public function getRemoteSocketAddress(){
		return $this->remoteAddr;
	}

	/**
	 * Sets inetAddress by host name or ip
	 * 
	 * @param	string $addr
	 * @throws	UnknownHostException
	 */
	private function findHost($addr) {
		try {
			return $this->findByHost($addr);
		} catch (UnknownHostException $uhe) {
			return $this->findByIp($addr);
		}
	}

	/**
	 * Sets a host and tries to resolve IP address. If Ip is valid adds it to List of ip
	 * 
	 * @param	string $sHost
	 * @throws	UnknownHostException
	 */
	private function findByHost($sHost){
		if (strlen($sHost) == 0)
			$this->error("setByIp argument invalid.");

		return InetAddress::getByName($sHost);
	}

	/**
	 * Sets Ip addres
	 * @param	string $sIp - (xxx.xxx.xxx.xxx)
	 * @throws	UnknownHostException
	 */
	private function findByIp($sIp){
		if (strlen($sIp) == 0)
			$this->error("setByIp argument invalid.");

		return InetAddress::getByAddress($sIp);
	}
	
	/**
	 * Set socket based on socket connection resource
	 * 
	 * @param	resource $rsc
	 * @return	InetSocketAddress
	 * @throws	SocketException
	 */
	protected function getSocketAddressByResource($rsc, $side=1) {
		if (!$rsc)
			$this->error("Cannot set socket by resource");
    
		$ip = null;
		$port = null;
		if ($side == 1) {
			if (!@socket_getpeername($rsc, $ip, $port))
				$this->error();
		} else {
			if (!@socket_getsockname($rsc, $ip, $port))
				$this->error();
		}
		
		$inetAddr = $this->findByIp($ip);
		return new InetSocketAddress($inetAddr, $port);
	}

	/**
	 * Set socket host and port
	 * 
	 * @param	mixed $sHost - The host can be a InetAddress or InetSocketAddress
	 * 			or string or socket resource.
	 * @param	int $iPort - Used if sHost is an InetAddress or string.
	 */
	private function set($sHost=null,$iPort=null) {
		if (is_object($sHost)) {
			if ($sHost instanceof InetAddress) {
				$this->remoteAddr = new InetSocketAddress($sHost, (int)$iPort);
			} else if ($sHost instanceof InetSocketAddress) {
				$this->remoteAddr = $sHost;
			} else {
				throw new SocketException("Invalid class address");
			}
		} else if (is_string($sHost)) {
			$inetAddr = $this->findHost($sHost);
			$this->remoteAddr = new InetSocketAddress($inetAddr, (int)$iPort);
		}
	}
	
	/**
	 * Open socket connection
	 *
	 * @param	mixed $sHost - The host can be a InetAddress or InetSocketAddress
	 * 			or string or socket resource.
	 * @param	int $iPort - Used if sHost is an InetAddress or string.
	 * @throws	SocketException
	 */
	public function open($sHost=null,$iPort=null) {
		$this->set($sHost, $iPort);
		$i = 0;
		$addrs = InetAddress::getAllByName($this->remoteAddr->getHostName());
		do {
			if (@socket_connect($this->hnd, $addrs[$i]->getAddress(), $this->remoteAddr->getPort()))
				$this->bConnected 	= true;
		} while (!$this->bConnected && $i++ < count($addrs));
		$this->error();
		
		$this->socketAddr = $this->getSocketAddressByResource($this->hnd, 2);
	}

	/**
	 * Connect with  host (open alias)
	 * 
	 * @param	mixed $sHost - The host can be a InetAddress or InetSocketAddress
	 * 			or string or socket resource.
	 * @param	int $iPort - Used if sHost is an InetAddress or string.
	 * @throws	SocketException
	 */
	public function connect($sHost=null,$iPort=null) {
		return $this->open($sHost, $iPort);
	}

	public function isConnected() {
		return $this->bConnected;
	}

	/**
	 * Send data
	 * If $sBuf is not empty try to send $sBuf, else try with $this->sBuffer
	 *
	 * @param	string $sBuf
	 * @param	int $iTimeOut
	 * @throws	SocketException
	 */
	public function send($sBuf,$iTimeOut=null){
		if (strlen($this->sBuffer) == 0 && strlen($sBuf) == 0)
			$this->error("Empty buffer");
		if (!$this->bConnected)
			$this->error("Cannot send data on a closed socket.");

		$vWrite = array($this->hnd);

		$WriteTimeOut = (strlen($iTimeOut)) ? $iTimeOut : $this->iWriteTimeOut;
		while (($rr = @socket_select($vRead = null, $vWrite, $vExcept = null, $WriteTimeOut)) === false);

		if ($rr == 0)
			$this->error("Call system select failed");

		$tmpBuf		= strlen($sBuf) ? $sBuf : $this->sBuffer;
		$iBufLen	= strlen($tmpBuf);
		$res 		= @socket_send($this->hnd,$tmpBuf,$iBufLen,0);

		if ($res === false) {
			$this->error();
		} else if ($res < $iBufLen) {
			$tmpBuf = substr($tmpBuf,$res);
			$this->send($tmpBuf);
		}
	}

	/**
	 * Send alias
	 *
	 * @param	string $sBuf
	 * @param	int $iTimeOut
	 */
	public function write($sBuf,$iTimeOut=null) {
		return $this->send($sBuf,$iTimeOut);
	}

	/**
	 * Read data from socket
	 *
	 * @param	int $iTimeOut
	 * @return	string
	 * @throws	SocketException
	 */
	public function recv($iTimeOut=null) {
		if (!$this->bConnected)
			$this->error("Cannot read any data on a closed socket.");

		$vSocket		= array($this->hnd);
		$this->sBuffer 	= null;
		$buf			= null;
		$ReadTimeOut	= (strlen($iTimeOut)) ? $iTimeOut : $this->iReadTimeOut;
		while (($rr = @socket_select($vSocket,$vWrite = null,$vExcept = null,$ReadTimeOut)) === false);

		if($rr == 0)
			$this->error("Call system select failed");

		$res = @socket_recv($this->hnd, $buf, self::READER_BUFFER,0);
		while ($res) {
			$this->sBuffer .=	$buf;
			$buf = null;

			while (($rr = @socket_select($vSocket,$vWrite = null, $vExcept = null, $ReadTimeOut)) === false);
			if ($rr == 0)
				break;

			$res = @socket_recv($this->hnd, $buf, self::READER_BUFFER, 0);
		}
		return $this->sBuffer;
	}

	/**
	 * Recv alias
	 *
	 * @param	int $iTimeOut
	 * @return	string
	 */
	public function read($iTimeOut=null){
		return $this->recv($iTimeOut);
	}

	/**
	 * Send data and wait response
	 *
	 * @param	string $sBuf
	 * @return	string
	 */
	public function sendAndWait($sBuf) {
		$this->send($sBuf);
		return $this->recv();
	}
}
?>
Return current item: Client and Server Socket