Heim  >  Artikel  >  Backend-Entwicklung  >  PHP WebSocket 客户端类 WebSocketClient

PHP WebSocket 客户端类 WebSocketClient

WBOY
WBOYOriginal
2016-06-20 12:41:541813Durchsuche

<?phpnamespace Common\Library;// ini_set('display_errors', 1);// error_reporting(E_ALL);/** * Very basic websocket client. * Supporting draft hybi-10.  *  * @author Simon Samtleben <web@lemmingzshadow.net> * @version 2011-10-18 */class WebSocketClient{	private $_host;	private $_port;	private $_path;	private $_origin;	private $_Socket = null;	private $_connected = false;		public function __construct() { }		public function __destruct()	{		$this->disconnect();	}	public function sendData($data, $type = 'text', $masked = true)	{		if($this->_connected === false)		{			trigger_error("Not connected", E_USER_WARNING);			return false;		}				if( !is_string($data)) {			trigger_error("Not a string data was given.", E_USER_WARNING);			return false;				}		if (strlen($data) == 0)		{			return false;		}		$res = @fwrite($this->_Socket, $this->_hybi10Encode($data, $type, $masked));				if($res === 0 || $res === false)		{			return false;		}				$buffer = ' ';		while($buffer !== '')		{						$buffer = fread($this->_Socket, 512);		}		return true;	}	public function connect($host, $port, $path, $origin = false)	{		$this->_host = $host;		$this->_port = $port;		$this->_path = $path;		$this->_origin = $origin;				$key = base64_encode($this->_generateRandomString(16, false, true));						$header = "GET " . $path . " HTTP/1.1\r\n";		$header.= "Host: ".$host.":".$port. "\r\n";		$header.= "Upgrade: websocket\r\n";		$header.= "Connection: Upgrade\r\n";		//$header.= "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n";		$header.= "Sec-WebSocket-Key: " . $key . "\r\n";		if($origin !== false)		{			$header.= "Sec-WebSocket-Origin: " . $origin . "\r\n";		}		$header.= "Sec-WebSocket-Version: 13\r\n\r\n";				$this->_Socket = fsockopen($host, $port, $errno, $errstr, 2);		socket_set_timeout($this->_Socket, 2, 10000);		//socket_write($this->_Socket, $header);		$res = @fwrite($this->_Socket, $header);		if( $res === false ){			echo "fwrite false \n";		}				$response = @fread($this->_Socket, 1500);		//$response = socket_read($this->_Socket);		preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $response, $matches);		if ($matches) {			$keyAccept = trim($matches[1]);			$expectedResonse = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));			$this->_connected = ($keyAccept === $expectedResonse) ? true : false;		}		return $this->_connected;	}		public function checkConnection()	{		$this->_connected = false;				// send ping:		$data = 'ping?';		@fwrite($this->_Socket, $this->_hybi10Encode($data, 'ping', true));		$response = @fread($this->_Socket, 300);		if(empty($response))		{						return false;		}		$response = $this->_hybi10Decode($response);		if(!is_array($response))		{						return false;		}		if(!isset($response['type']) || $response['type'] !== 'pong')		{						return false;		}		$this->_connected = true;		return true;	}	public function disconnect()	{		$this->_connected = false;		is_resource($this->_Socket) and fclose($this->_Socket);	}		public function reconnect()	{		sleep(10);		$this->_connected = false;		fclose($this->_Socket);		$this->connect($this->_host, $this->_port, $this->_path, $this->_origin);			}	private function _generateRandomString($length = 10, $addSpaces = true, $addNumbers = true)	{  		$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"ยง$%&/()=[]{}';		$useChars = array();		// select some random chars:    		for($i = 0; $i < $length; $i++)		{			$useChars[] = $characters[mt_rand(0, strlen($characters)-1)];		}		// add spaces and numbers:		if($addSpaces === true)		{			array_push($useChars, ' ', ' ', ' ', ' ', ' ', ' ');		}		if($addNumbers === true)		{			array_push($useChars, rand(0,9), rand(0,9), rand(0,9));		}		shuffle($useChars);		$randomString = trim(implode('', $useChars));		$randomString = substr($randomString, 0, $length);		return $randomString;	}		private function _hybi10Encode($payload, $type = 'text', $masked = true)	{		$frameHead = array();		$frame = '';		$payloadLength = strlen($payload);				switch($type)		{					case 'text':				// first byte indicates FIN, Text-Frame (10000001):				$frameHead[0] = 129;							break;								case 'close':				// first byte indicates FIN, Close Frame(10001000):				$frameHead[0] = 136;			break;					case 'ping':				// first byte indicates FIN, Ping frame (10001001):				$frameHead[0] = 137;			break;					case 'pong':				// first byte indicates FIN, Pong frame (10001010):				$frameHead[0] = 138;			break;		}				// set mask and payload length (using 1, 3 or 9 bytes) 		if($payloadLength > 65535)		{			$payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);			$frameHead[1] = ($masked === true) ? 255 : 127;			for($i = 0; $i < 8; $i++)			{				$frameHead[$i+2] = bindec($payloadLengthBin[$i]);			}			// most significant bit MUST be 0 (close connection if frame too big)			if($frameHead[2] > 127)			{				$this->close(1004);				return false;			}		}		elseif($payloadLength > 125)		{			$payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);			$frameHead[1] = ($masked === true) ? 254 : 126;			$frameHead[2] = bindec($payloadLengthBin[0]);			$frameHead[3] = bindec($payloadLengthBin[1]);		}		else		{			$frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;		}		// convert frame-head to string:		foreach(array_keys($frameHead) as $i)		{			$frameHead[$i] = chr($frameHead[$i]);		}		if($masked === true)		{			// generate a random mask:			$mask = array();			for($i = 0; $i < 4; $i++)			{				$mask[$i] = chr(rand(0, 255));			}						$frameHead = array_merge($frameHead, $mask);					}								$frame = implode('', $frameHead);		// append payload to frame:		$framePayload = array();			for($i = 0; $i < $payloadLength; $i++)		{					$frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];		}		return $frame;	}		private function _hybi10Decode($data)	{		$payloadLength = '';		$mask = '';		$unmaskedPayload = '';		$decodedData = array();				// estimate frame type:		$firstByteBinary = sprintf('%08b', ord($data[0]));				$secondByteBinary = sprintf('%08b', ord($data[1]));		$opcode = bindec(substr($firstByteBinary, 4, 4));		$isMasked = ($secondByteBinary[0] == '1') ? true : false;		$payloadLength = ord($data[1]) & 127;						switch($opcode)		{			// text frame:			case 1:				$decodedData['type'] = 'text';							break;					case 2:				$decodedData['type'] = 'binary';			break;						// connection close frame:			case 8:				$decodedData['type'] = 'close';			break;						// ping frame:			case 9:				$decodedData['type'] = 'ping';							break;						// pong frame:			case 10:				$decodedData['type'] = 'pong';			break;						default:				return false;			break;		}				if($payloadLength === 126)		{		   $mask = substr($data, 4, 4);		   $payloadOffset = 8;		   $dataLength = bindec(sprintf('%08b', ord($data[2])) . sprintf('%08b', ord($data[3]))) + $payloadOffset;		}		elseif($payloadLength === 127)		{			$mask = substr($data, 10, 4);			$payloadOffset = 14;			$tmp = '';			for($i = 0; $i < 8; $i++)			{				$tmp .= sprintf('%08b', ord($data[$i+2]));			}			$dataLength = bindec($tmp) + $payloadOffset;			unset($tmp);		}		else		{			$mask = substr($data, 2, 4);				$payloadOffset = 6;			$dataLength = $payloadLength + $payloadOffset;		}					if($isMasked === true)		{			for($i = $payloadOffset; $i < $dataLength; $i++)			{				$j = $i - $payloadOffset;				if(isset($data[$i]))				{					$unmaskedPayload .= $data[$i] ^ $mask[$j % 4];				}			}			$decodedData['payload'] = $unmaskedPayload;		}		else		{			$payloadOffset = $payloadOffset - 4;			$decodedData['payload'] = substr($data, $payloadOffset);		}				return $decodedData;	}}


使用示例:

// 使用 WebSocket 通知客户端		$client = new \Common\Library\WebSocketClient();		$client->connect($_SERVER['HTTP_HOST'], 943, '/');			$payload = json_encode(array(			'code' => 'xxx',			'id' => '1'		));		$rs = $client->sendData($payload);			if( $rs !== true ){			echo "sendData error...\n";		}else{			echo "ok\n";		}


来自: http://my.oschina.net/skq/blog/552923

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn