websocket百度云 php,PHP WebSocket 客户端类 WebSocketClient

namespace Common\Library;

// ini_set('display_errors', 1);

// error_reporting(E_ALL);

/**

* Very basic websocket client.

* Supporting draft hybi-10.

*

* @author Simon Samtleben 

* @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 

{

$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 

{

$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 

{

$mask[$i] = chr(rand(0, 255));

}

$frameHead = array_merge($frameHead, $mask);

}

$frame = implode('', $frameHead);

// append payload to frame:

$framePayload = array();

for($i = 0; $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 

{

$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 

{

$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";

}

相关:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值