You've already forked qlg.tsgz.moe
Init Repo
This commit is contained in:
307
vendor/swoole/examples/websocket/WebSocketClient.php
vendored
Executable file
307
vendor/swoole/examples/websocket/WebSocketClient.php
vendored
Executable file
@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
class WebSocketClient
|
||||
{
|
||||
const VERSION = '0.1.4';
|
||||
|
||||
const TOKEN_LENGHT = 16;
|
||||
const TYPE_ID_WELCOME = 0;
|
||||
const TYPE_ID_PREFIX = 1;
|
||||
const TYPE_ID_CALL = 2;
|
||||
const TYPE_ID_CALLRESULT = 3;
|
||||
const TYPE_ID_ERROR = 4;
|
||||
const TYPE_ID_SUBSCRIBE = 5;
|
||||
const TYPE_ID_UNSUBSCRIBE = 6;
|
||||
const TYPE_ID_PUBLISH = 7;
|
||||
const TYPE_ID_EVENT = 8;
|
||||
|
||||
const OPCODE_CONTINUATION_FRAME = 0x0;
|
||||
const OPCODE_TEXT_FRAME = 0x1;
|
||||
const OPCODE_BINARY_FRAME = 0x2;
|
||||
const OPCODE_CONNECTION_CLOSE = 0x8;
|
||||
const OPCODE_PING = 0x9;
|
||||
const OPCODE_PONG = 0xa;
|
||||
|
||||
const CLOSE_NORMAL = 1000;
|
||||
const CLOSE_GOING_AWAY = 1001;
|
||||
const CLOSE_PROTOCOL_ERROR = 1002;
|
||||
const CLOSE_DATA_ERROR = 1003;
|
||||
const CLOSE_STATUS_ERROR = 1005;
|
||||
const CLOSE_ABNORMAL = 1006;
|
||||
const CLOSE_MESSAGE_ERROR = 1007;
|
||||
const CLOSE_POLICY_ERROR = 1008;
|
||||
const CLOSE_MESSAGE_TOO_BIG = 1009;
|
||||
const CLOSE_EXTENSION_MISSING = 1010;
|
||||
const CLOSE_SERVER_ERROR = 1011;
|
||||
const CLOSE_TLS = 1015;
|
||||
|
||||
private $key;
|
||||
private $host;
|
||||
private $port;
|
||||
private $path;
|
||||
/**
|
||||
* @var swoole_client
|
||||
*/
|
||||
private $socket;
|
||||
private $buffer = '';
|
||||
private $origin = null;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $connected = false;
|
||||
|
||||
public $returnData = false;
|
||||
|
||||
/**
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param string $path
|
||||
*/
|
||||
function __construct($host = '127.0.0.1', $port = 8080, $path = '/', $origin = null)
|
||||
{
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->path = $path;
|
||||
$this->origin = $origin;
|
||||
$this->key = $this->generateToken(self::TOKEN_LENGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect on destruct
|
||||
*/
|
||||
function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect client to server
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
$this->socket = new \swoole_client(SWOOLE_SOCK_TCP);
|
||||
if (!$this->socket->connect($this->host, $this->port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$this->socket->send($this->createHeader());
|
||||
return $this->recv();
|
||||
}
|
||||
|
||||
public function getSocket()
|
||||
{
|
||||
return $this->socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from server
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->connected = false;
|
||||
$this->socket->close();
|
||||
}
|
||||
|
||||
public function close($code = self::CLOSE_NORMAL, $reason = '')
|
||||
{
|
||||
$data = pack('n', $code) . $reason;
|
||||
return $this->socket->send(swoole_websocket_server::pack($data, self::OPCODE_CONNECTION_CLOSE, true));
|
||||
}
|
||||
|
||||
public function recv()
|
||||
{
|
||||
$data = $this->socket->recv();
|
||||
if ($data === false)
|
||||
{
|
||||
echo "Error: {$this->socket->errMsg}";
|
||||
return false;
|
||||
}
|
||||
$this->buffer .= $data;
|
||||
$recv_data = $this->parseData($this->buffer);
|
||||
if ($recv_data)
|
||||
{
|
||||
$this->buffer = '';
|
||||
return $recv_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param string $type
|
||||
* @param bool $masked
|
||||
* @return bool
|
||||
*/
|
||||
public function send($data, $type = 'text', $masked = false)
|
||||
{
|
||||
switch($type)
|
||||
{
|
||||
case 'text':
|
||||
$_type = WEBSOCKET_OPCODE_TEXT;
|
||||
break;
|
||||
case 'binary':
|
||||
case 'bin':
|
||||
$_type = WEBSOCKET_OPCODE_BINARY;
|
||||
break;
|
||||
case 'ping':
|
||||
$_type = WEBSOCKET_OPCODE_PING;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return $this->socket->send(swoole_websocket_server::pack($data, $_type, true, $masked));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse received data
|
||||
*
|
||||
* @param $response
|
||||
*/
|
||||
private function parseData($response)
|
||||
{
|
||||
if (!$this->connected)
|
||||
{
|
||||
$response = $this->parseIncomingRaw($response);
|
||||
if (isset($response['Sec-Websocket-Accept'])
|
||||
&& base64_encode(pack('H*', sha1($this->key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))) === $response['Sec-Websocket-Accept']
|
||||
)
|
||||
{
|
||||
$this->connected = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception("error response key.");
|
||||
}
|
||||
}
|
||||
|
||||
$frame = swoole_websocket_server::unpack($response);
|
||||
if ($frame)
|
||||
{
|
||||
return $this->returnData ? $frame->data : $frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception("swoole_websocket_server::unpack failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create header for websocket client
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createHeader()
|
||||
{
|
||||
$host = $this->host;
|
||||
if ($host === '127.0.0.1' || $host === '0.0.0.0')
|
||||
{
|
||||
$host = 'localhost';
|
||||
}
|
||||
return "GET {$this->path} HTTP/1.1" . "\r\n" .
|
||||
"Origin: {$this->origin}" . "\r\n" .
|
||||
"Host: {$host}:{$this->port}" . "\r\n" .
|
||||
"Sec-WebSocket-Key: {$this->key}" . "\r\n" .
|
||||
"User-Agent: PHPWebSocketClient/" . self::VERSION . "\r\n" .
|
||||
"Upgrade: websocket" . "\r\n" .
|
||||
"Connection: Upgrade" . "\r\n" .
|
||||
"Sec-WebSocket-Protocol: wamp" . "\r\n" .
|
||||
"Sec-WebSocket-Version: 13" . "\r\n" . "\r\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse raw incoming data
|
||||
*
|
||||
* @param $header
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseIncomingRaw($header)
|
||||
{
|
||||
$retval = array();
|
||||
$content = "";
|
||||
$fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
if (preg_match('/([^:]+): (.+)/m', $field, $match))
|
||||
{
|
||||
$match[1] = preg_replace_callback('/(?<=^|[\x09\x20\x2D])./',
|
||||
function ($matches)
|
||||
{
|
||||
return strtoupper($matches[0]);
|
||||
},
|
||||
strtolower(trim($match[1])));
|
||||
if (isset($retval[$match[1]]))
|
||||
{
|
||||
$retval[$match[1]] = array($retval[$match[1]], $match[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval[$match[1]] = trim($match[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match('!HTTP/1\.\d (\d)* .!', $field))
|
||||
{
|
||||
$retval["status"] = $field;
|
||||
}
|
||||
else
|
||||
{
|
||||
$content .= $field . "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
$retval['content'] = $content;
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate token
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateToken($length)
|
||||
{
|
||||
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}';
|
||||
$useChars = array();
|
||||
// select some random chars:
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$useChars[] = $characters[mt_rand(0, strlen($characters) - 1)];
|
||||
}
|
||||
// Add numbers
|
||||
array_push($useChars, rand(0, 9), rand(0, 9), rand(0, 9));
|
||||
shuffle($useChars);
|
||||
$randomString = trim(implode('', $useChars));
|
||||
$randomString = substr($randomString, 0, self::TOKEN_LENGHT);
|
||||
return base64_encode($randomString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate token
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateAlphaNumToken($length)
|
||||
{
|
||||
$characters = str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
|
||||
srand((float)microtime() * 1000000);
|
||||
$token = '';
|
||||
do
|
||||
{
|
||||
shuffle($characters);
|
||||
$token .= $characters[mt_rand(0, (count($characters) - 1))];
|
||||
} while (strlen($token) < $length);
|
||||
return $token;
|
||||
}
|
||||
}
|
11
vendor/swoole/examples/websocket/async_client.php
vendored
Executable file
11
vendor/swoole/examples/websocket/async_client.php
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
$cli = new swoole_http_client('127.0.0.1', 9501);
|
||||
$cli->setHeaders(['Trace-Id' => md5(time()),]);
|
||||
$cli->on('message', function ($_cli, $frame) {
|
||||
var_dump($frame);
|
||||
});
|
||||
|
||||
$cli->upgrade('/', function ($cli) {
|
||||
echo $cli->body;
|
||||
$cli->push("hello world");
|
||||
});
|
19
vendor/swoole/examples/websocket/client.html
vendored
Executable file
19
vendor/swoole/examples/websocket/client.html
vendored
Executable file
@ -0,0 +1,19 @@
|
||||
<script>
|
||||
var wsServer = 'ws://127.0.0.1:9501';
|
||||
var websocket = new WebSocket(wsServer);
|
||||
websocket.onopen = function (evt) {
|
||||
console.log("Connected to WebSocket server.");
|
||||
};
|
||||
|
||||
websocket.onclose = function (evt) {
|
||||
console.log("Disconnected");
|
||||
};
|
||||
|
||||
websocket.onmessage = function (evt) {
|
||||
console.log('Retrieved data from server: ' + evt.data);
|
||||
};
|
||||
|
||||
websocket.onerror = function (evt, e) {
|
||||
console.log('Error occured: ' + evt.data);
|
||||
};
|
||||
</script>
|
40
vendor/swoole/examples/websocket/client.php
vendored
Executable file
40
vendor/swoole/examples/websocket/client.php
vendored
Executable file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
$opt = getopt("c:n:k:");
|
||||
print_r($opt);
|
||||
if (empty($opt['c']) || empty($opt['n']))
|
||||
{
|
||||
echo "examples: php client.php -c 100 -n 10000" . PHP_EOL;
|
||||
return;
|
||||
}
|
||||
$clients = $opt['c'];
|
||||
$count = $opt['n'];
|
||||
$size = empty($opt['k']) ? 0 : $opt['k'];
|
||||
require __DIR__ . "/WebSocketClient.php";
|
||||
$host = '127.0.0.1';
|
||||
$prot = 9501;
|
||||
|
||||
$client = new WebSocketClient($host, $prot);
|
||||
$data = $client->connect();
|
||||
//echo $data;
|
||||
$data = "data";
|
||||
if (!empty($size))
|
||||
{
|
||||
$data = str_repeat("A", $size * 1024);
|
||||
}
|
||||
for ($i = 0; $i < $count; $i++)
|
||||
{
|
||||
$client->send("hello swoole, number:" . $i . " data:" . $data);
|
||||
$recvData = "";
|
||||
//while(1) {
|
||||
$tmp = $client->recv();
|
||||
if (empty($tmp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
$recvData .= $tmp;
|
||||
//}
|
||||
echo $recvData . "size:" . strlen($recvData) . PHP_EOL;
|
||||
}
|
||||
echo PHP_EOL . "======" . PHP_EOL;
|
||||
sleep(1);
|
||||
echo 'finish' . PHP_EOL;
|
138
vendor/swoole/examples/websocket/server.php
vendored
Executable file
138
vendor/swoole/examples/websocket/server.php
vendored
Executable file
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
//$server = new swoole_websocket_server("0.0.0.0", 9501);
|
||||
$server = new swoole_websocket_server("0.0.0.0", 9501, SWOOLE_BASE);
|
||||
//$server->addlistener('0.0.0.0', 9502, SWOOLE_SOCK_UDP);
|
||||
//$server->set(['worker_num' => 4,
|
||||
// 'task_worker_num' => 4,
|
||||
//]);
|
||||
|
||||
function user_handshake(swoole_http_request $request, swoole_http_response $response)
|
||||
{
|
||||
//自定定握手规则,没有设置则用系统内置的(只支持version:13的)
|
||||
if (!isset($request->header['sec-websocket-key']))
|
||||
{
|
||||
//'Bad protocol implementation: it is not RFC6455.'
|
||||
$response->end();
|
||||
return false;
|
||||
}
|
||||
if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key'])
|
||||
|| 16 !== strlen(base64_decode($request->header['sec-websocket-key']))
|
||||
)
|
||||
{
|
||||
//Header Sec-WebSocket-Key is illegal;
|
||||
$response->end();
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = base64_encode(sha1($request->header['sec-websocket-key']
|
||||
. '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
||||
true));
|
||||
$headers = array(
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Accept' => $key,
|
||||
'Sec-WebSocket-Version' => '13',
|
||||
'KeepAlive' => 'off',
|
||||
);
|
||||
foreach ($headers as $key => $val)
|
||||
{
|
||||
$response->header($key, $val);
|
||||
}
|
||||
$response->status(101);
|
||||
$response->end();
|
||||
global $server;
|
||||
$fd = $request->fd;
|
||||
$server->defer(function () use ($fd, $server)
|
||||
{
|
||||
$server->push($fd, "hello, welcome\n");
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
$server->on('handshake', 'user_handshake');
|
||||
$server->on('open', function (swoole_websocket_server $_server, swoole_http_request $request) {
|
||||
echo "server#{$_server->worker_pid}: handshake success with fd#{$request->fd}\n";
|
||||
var_dump($_server->exist($request->fd), $_server->getClientInfo($request->fd));
|
||||
// var_dump($request);
|
||||
});
|
||||
|
||||
$server->on('message', function (swoole_websocket_server $_server, $frame) {
|
||||
var_dump($frame->data);
|
||||
echo "received ".strlen($frame->data)." bytes\n";
|
||||
if ($frame->data == "close")
|
||||
{
|
||||
$_server->close($frame->fd);
|
||||
}
|
||||
elseif($frame->data == "task")
|
||||
{
|
||||
$_server->task(['go' => 'die']);
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "receive from {$frame->fd}:{$frame->data}, opcode:{$frame->opcode}, finish:{$frame->finish}\n";
|
||||
// for ($i = 0; $i < 100; $i++)
|
||||
{
|
||||
$_send = str_repeat('B', rand(100, 800));
|
||||
$_server->push($frame->fd, $_send);
|
||||
// echo "#$i\tserver sent " . strlen($_send) . " byte \n";
|
||||
}
|
||||
$fd = $frame->fd;
|
||||
$_server->tick(2000, function($id) use ($fd, $_server) {
|
||||
$_send = str_repeat('B', rand(100, 5000));
|
||||
$ret = $_server->push($fd, $_send);
|
||||
if (!$ret)
|
||||
{
|
||||
var_dump($id);
|
||||
var_dump($_server->clearTimer($id));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$server->on('close', function ($_server, $fd) {
|
||||
echo "client {$fd} closed\n";
|
||||
});
|
||||
|
||||
$server->on('task', function ($_server, $worker_id, $task_id, $data)
|
||||
{
|
||||
var_dump($worker_id, $task_id, $data);
|
||||
return "hello world\n";
|
||||
});
|
||||
|
||||
$server->on('finish', function ($_server, $task_id, $result)
|
||||
{
|
||||
var_dump($task_id, $result);
|
||||
});
|
||||
|
||||
$server->on('packet', function ($_server, $data, $client) {
|
||||
echo "#".posix_getpid()."\tPacket {$data}\n";
|
||||
var_dump($client);
|
||||
});
|
||||
|
||||
$server->on('request', function (swoole_http_request $request, swoole_http_response $response) {
|
||||
$response->end(<<<HTML
|
||||
<h1>Swoole WebSocket Server</h1>
|
||||
<script>
|
||||
var wsServer = 'ws://127.0.0.1:9501';
|
||||
var websocket = new WebSocket(wsServer);
|
||||
websocket.onopen = function (evt) {
|
||||
console.log("Connected to WebSocket server.");
|
||||
};
|
||||
|
||||
websocket.onclose = function (evt) {
|
||||
console.log("Disconnected");
|
||||
};
|
||||
|
||||
websocket.onmessage = function (evt) {
|
||||
console.log('Retrieved data from server: ' + evt.data);
|
||||
};
|
||||
|
||||
websocket.onerror = function (evt, e) {
|
||||
console.log('Error occured: ' + evt.data);
|
||||
};
|
||||
</script>
|
||||
HTML
|
||||
);
|
||||
});
|
||||
|
||||
$server->start();
|
Reference in New Issue
Block a user