Архив метки: WebSocket

Нагрузочное тестирование сайта с помощью Jmeter

Задача: провести нагрузочное тестирование сайта. Выяснить сколько пользователей в минуту, он может обслужить.

Дополнительно: тестирование сервера WEBSocket, так-же используемого на том-же сервере, где и расположен сайт.

Решение: используем инструмент Jmeter от фонда Apache.

1) Скачиваем, распаковываем, запускаем из папки bin или файл jmeter.bat (Windows) или jmeter.sh (Linux)

2) На сайте плагинов скачиваем плагины Plugins Manager и JMeterWebSocketSamplers. Ложим их в папку lib\ext, Jmeter перезапускаем. При помощи Plugins Manage, в дальнейшем (если захотите) сможете устанавливать дополнительные плагины.

3) Правой клавишей щелкаем по TestPlan, и создаем поток тестирования.

Далее в настройках выставляем количество потоков, время тестирования и количество циклов

4) Добавляем авторизацию на сайте (ну или просто открытие страницы — тогда POST запрос не заполняем)

 

К этому же узлу добавим и отчетность:

5) По тому-же принципу последовательно добавляем задачи WebSocketOpen,WebSocketSingleWrite и WebSocketClose. Т.е. после авторизации пользователя мы откроем соединение, пошлем что-то на сервер и закроем соединение.

Далее играем циферками количества поток, чтобы выяснить на скольких потоках сайт упадет отдохнуть..

 

WebSocket Ratchet сервер с одновременной прослушкой двух IP

Задача: поднять WebSocket сервер, одновременно слущающий и wss (для браузеров) и ws (для скриптов на PHP на том-же сервере).

Почему такой велосипед? Ну просто вот ну никак не удалось подобрать WebSocket клиент на PHP нормально работающий с WSS (SSL).

Решение:

$myClassMessage=new MessageService($UsersApi);

$loop = React\EventLoop\Factory::create();
$webSock = new React\Socket\Server('0.0.0.0:35500', $loop);
$webSock = new React\Socket\SecureServer($webSock, $loop, [
    'local_cert'        => 'епкуеп.crt', // path to your cert
    'local_pk'          => 'кепуке.key', // path to your server private key
    'allow_self_signed' => TRUE, // Allow self signed certs (should be false in production)
    'verify_peer' => FALSE
]);

$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            $myClassMessage
        )
    ),
    $webSock,
    $loop        
);
$webSock2 = new React\Socket\Server('127.0.0.1:35501', $loop);

$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            $myClassMessage
        )
    ),
    $webSock2,
    $loop        
);
$loop->run();

websocket сервер ratchet c SSL

Почемуто большинство примеров создания websocket сервера с использованием ratchet приведены без использования SSL.  И у всех как я почитаю пляски с буном потом с проксированием через apache или ngnix. Но ведь он умеет и без этого!

Вот примерно как это оформляется:

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\Factory;
use React\Socket\SecureServer; 

$loop = React\EventLoop\Factory::create();
$webSock = new React\Socket\Server('0.0.0.0:33423', $loop);
$webSock = new React\Socket\SecureServer($webSock, $loop, [
    'local_cert'        => 'sssss.crt', 
    'local_pk'          => 'sssss.key', 
    'allow_self_signed' => TRUE, 
    'verify_peer' => FALSE
]);

$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            new MessageService($UsersApi)
        )
    ),
    $webSock,
    $loop        
);

$webServer->run();

А вот пример класса MessageService:

class MessageService implements MessageComponentInterface {
    protected $clients;
    public $cnt=0; 
    public $uapi="";
    public function __construct($uu) {
        $this->uapi=$uu;
        $this->clients = array();        
        echo "- запустили, ждем соединения..\n";
    }

    public function onOpen(ConnectionInterface $conn) {                
            $user["user"]="";
            $user["conn"]=$conn;
            $this->clients[]=$user;
            $this->cnt++;            
            echo "--с нами ".count($this->clients)."\n";
            echo "---спрашиваю who_are_you?\n";
            $conn->send(json_encode(array("command"=>"who_are_you")));
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        echo "-- пришло сообщение: $msg \n";        
        $msg= json_decode($msg);
        //var_dump($msg);
        if (isset($msg->command)):
            switch ($msg->command) {
               case "who_am_i":
               // обхожу все соединения, и добавляю параметр - пришедший id пользователя
                    foreach ($this->clients as &$client) {
                        if ($from == $client["conn"]) {
                            $client["user"]=$msg->user;
                        };
                    };
               break;
               default:break;
            }
        endif;

    }

    public function onClose(ConnectionInterface $conn) { 
        $user="";
        foreach ($this->clients as $key=>$client) {          
          if ($client["conn"]==$conn):
              echo "-- ушел $key(".$client["user"].")\n";              
              $user=$client["user"];
              unset($this->clients[$key]);              
          endif;
        };
        echo "-- осталось соединений ".count($this->clients)."\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        $conn->close();
    }
}

Пример клиента WebSocket на PHP

Если клиент на javascript для WebSocket это весьма простая вещь, то на PHP чуточку сложнее. Готовых примеров в сети раз-два и обчелся. Вот пример одной из реализаций:

 

$local = "http://грибовы.рф";		    
$data = "Скрипт обработки выбора фильтра абонентом";  
$key="woeudhцукацук цук пупркеркеуенakcslerug;er";

	$host=$row2["mysql_ip"];
	$port = 8000;
	$head = "GET / HTTP/1.1"."\r\n".
		"Upgrade: WebSocket"."\r\n".
		"Connection: Upgrade"."\r\n".
		"Origin: $local"."\r\n".
		"Host: $host"."\r\n".
		"Sec-WebSocket-Key: asd245345235d6asd6as7d"."\r\n".
		"Content-Length: ".strlen($data)."\r\n"."\r\n";
	
	$sock = fsockopen($host, $port, $errno, $errstr, 2);
	fwrite($sock, $head ) or die('error:'.$errno.':'.$errstr);
	$headers = fread($sock, 2000);
	//echo $headers;
	fwrite($sock, hybi10Encode($data)) or die('error:'.$errno.':'.$errstr);
	$wsdata = fread($sock, 2000);
	//var_dump(hybi10Decode($wsdata));
	//echo "--send\n";    
	    $mess["key"]=$key;
	    $mess["command"]="UpdateFilterContent";
	    fwrite($sock, hybi10Encode(json_encode($mess))) or die('error:'.$errno.':'.$errstr);
	//echo "--read\n";        
	$wsdata = fread($sock, 2000);
	//var_dump(hybi10Decode($wsdata));
	fclose($sock);		

Вспомогательные функции:

Читать далее Пример клиента WebSocket на PHP

wss WebSocket через proxy apache

Возникла необходимость поднять соединение wss Websocket из браузера на странице с протоколом https. Причем сертификат для страницы — самоподписанный. Соответственно при первом заходе на такую страницу, браузер сообщает что страница не небезопасна и т.п. Когда пользователь соглашается, что согласен посетить данную страницу, открывается сайт, и скрипт на сайте пытается установить wss соединение с сервером по тому-же адресу, что и сам сайт. И соответственно не получается, т.к. пользователь страницы не одобрил это не безопасное соединение. Если он откроет в браузере ссылку вида https://websocketserver:8100, и согласится, то соединение будет установлено корректно. Но заставлять пользователя перед работой на сайте открывать еще одну страницу — бред. Можно поступить по другому: не заметно перенаправить соединение вида https://websocketserver/wss/ на ws://websocketserver:8100 . И вуаля — соединение теперь устанавливается без лишних вопросов.
Для того чтобы это всё работало, в настройках апача нужно включить модули: proxy_module и proxy_wstunnel_module. И в настройках сайта соответственно прописать чтото типа:

ProxyPass /chat/ ws://noc.dcedwedwe.ru:8100/
ProxyPassReverse /chat/ ws://noc.dcedwedwe.ru:8100/