morozovsk / websocket Goto Github PK
View Code? Open in Web Editor NEWsimple php websocket server + demos + yii/yii2 integration + php 7 support
simple php websocket server + demos + yii/yii2 integration + php 7 support
Здравствуйте!
Не нашел, как можно лично задать вам вопрос.
Попытался реализовать у себя сокет на примере первого чата. Не получается установить с ним подключение по сокету unix:///tmp/websocket.sock, про который вы говорите в статье http://habrahabr.ru/company/ifree/blog/210228/.
Например, пишу в index.php 'localsocket' => 'unix:///var/www/websocket.sock' , затем пытаюсь передать данные:
$fp = stream_socket_client("unix:///var/www/websocket.sock", $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)
\n";
} else {
fwrite($fp, "vsem privet"."\r\n");
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
}
Пишет, доступ запрещен, меняю права на 777, скрипт долго выполняется, но ничего не передается. Подскажите, пожалуйста, что я не так делаю?
Еще подскажите, пожалуйста, правильно ли я понимаю, уязвимости, про которые вам писали в комментариях, есть в первом чате, но исправлены во втором?
Проблема 1:
в Generic.php (для любых модулей) есть функции _read, _write, close которые могут заэррорить и сказать Call to undefined function read/write/disable on null, решается добавлением
if(!isset($this->buffers[$connectionId])) return;
в каждую из функций
Проблема 2:
Event, связанная с этой библиотекой, через время (прим. 15мин) $this->getIdByConnection($this->_master) отдает 0 (GenericEvent.php), думая что это не мастер, передача данных в функцию onMasterMessage не происходит, решил для себя добавлением возле
$this->onServiceMessage($connectionId, $data);
этого
$this->onMasterMessage($data);
Но лучше ждать оф. фикс от автора
Есть вопрос, как при подключении/отключении новых юзеров отображать изменения с списке онлайн юзеров? ведь сокет напрямую не связан с javascript на фронте? или можно как-то отправлять сообщения в json формате и обрабатывать отдельно текстовую часть, отдельно данные?
При работе в сафари js выдает ошибкуIndexSizeError (DOM Exception 1): The index is not in the allowed range.
У вас было такое? Можно включить чат сервер на демке, а то не получается протестить...
Кстати заметил что периодически чат сервер самопроизвольно отваливается, с чем это может быть связано?
Здравствуйте.
Используем примеры Chat3 и eventDriver=>event.
Со вчерашнего утра и по сегодняшнее коннекты только растут.
На текущий момент 3840.
То есть за ночь не сбросились.
Есть такая проблема и как бороть если есть?
Или это реальные коннекты и радоваться такому обстоятельству дел?
PS: Вопрос бонусом, если нужно создам Issue
В итоге в конфиге осталась одна закомментированная строка:
//'master' => 'tcp://127.0.0.1:8020',
Для чего она?
стал изучать Ваш demon и заметил что он наследуется от класса Generic но самого класса не нашел не нашел так же и следующих свойств
и метода
я так понимаю они должны быть в классе Generic и как сейчас без них работает Demon ?
Hi! Is it possible to get workaround?
PHP Fatal Error 'yii\base\ErrorException' with message 'Call to undefined function morozovsk\websocket\posix_getpid()'
in C:\wamp\www\flex\vendor\morozovsk\websocket\Server.php:61
привет! из коробки не работают POST-запросы с JSON-payload, корректно(а может и нет) работает вот такой апдейт GenericSelect (с 99 строки): http://pastebin.com/2M6U3C9v
Так же не очень понятно зачем вызывается колбэк onServiceMessage через каждый перенос строки... Использую, например, service как микро-веб-сервер для обработки входящих запросов с другого сервера и связи их(запросов) с вебсокетами. Так коряво - потому, что, опять же из коробки нельзя получить доступ к подключенным вебсокет-клиентам НЕ из текущего экземпляра компонента, т.е. приходится этих клиентов где-то хранить, апдейтить их статус...
Проблема 3: если пропадает соединение с вебсокет-клиентом, то при попытке ему что-то отослать (sendToClient), сервер падает целиком, не выбрасывая никакого исключения, с точки зрения парадигмы Yii - это не правильно... Обернув stream_select в проверку и try...catch в принципе это решается, но иногда дропает и из других неопределенных мест
Здравствуйте.
Хочу интегрировать ваше решение к себе на сайт.
Подскажите можно ли как то отправлять сообщение конкретно одному пользователю?
В примерах Чат3 - улучшенная вариация Чат2 ?
Спасибо.
Было б хорошо сделать управление сервером, остановку, статус и т.п.
А то чтобы остановить надо убивать процес, а после этого сервер не запускаеться, пишет что порт занат
This library works, but I will not develop and support it because I will use https://github.com/walkor/Workerman
почему бросили и почему именно Workerman? библиотека прям намного менее монстроузна, чем ratchet?
В этом методе https://github.com/morozovsk/websocket/blob/master/WebsocketGenericEvent.php#L51 , вы параметр $connection обрабатываете с помощью $this->getIdByConnection($connection);
Вопрос : В каких случаях $connection не int ?
Мой дамп при конекте:
var_dump([$listener, $connection, $address, $id]);
array(4) {
[0]=>
object(EventListener)#5 (1) {
["fd"]=> int(3)
}
[1]=> int(7)
[2]=>
array(2) {
[0]=> string(9) "127.0.0.1"
[1]=> int(60314)
}
[3]=>
object(EventBase)#4 (0) {
}
}
Добрый день!
Не подскажите, нет ли в планах адаптации библиотеки под PHP7? Или библиотека в текущем состоянии полностью совместима?
К тому же, буквально вчера (29.02.2016) вышла стабильная версия Event с поддержкой PHP7 - https://pecl.php.net/package/event
Во второй версии, судя по ченжлогу поправили утечки памяти (не знаю, может только у меня так, но на php 5.6.x с event после 14-15к коннектов, последующие коннекты начинают приниматься 1 через 5, перезапускаешь демона - все как по маслу, возвращаешься на socket_select - проблем нет.
Имеется скрипт следующего содержания:
pg_query($this->connection, 'LISTEN user_notify;');
while (1) {
$notify = pg_get_notify($this->connection);
if ($notify) {
var_dump(json_decode($notify['payload'], true));
}
}
Как появляется уведомление в канале user_notify - оно распечатывается. От библиотеки нужно что б она слушала этот канал и как там появлялись данные отсылала по клиентам. Вопрос: как подружить это с библиотекой?
Спасибо, за вашу работу.
Очень хотелось бы увидеть качественный пример исполнения данных примеров на в немного другой реализации, вместо модуля libevent использовать более качественный и удобный модуль Event (http://ua2.php.net/manual/ru/book.event.php)
вместо pcntl_fork, использовать Pthreads (http://docs.php.net/manual/ru/book.pthreads.php)
Или услышать ваше мнения про использования данных модулей, для этих задач?
Просто не хочется использовать тяжелые PHPDaemon и/или Ratchet.
Хочется самому реализовать, но сокеты и pcntl_fork довольно низко уровневое программирования и много кода, хочется использовать библиотеки более высокого уровня и на ООП.
Здравствуйте!
Хочу отправлять сообщения в чат из консоли, но не понимаю как это сделать. Можете помочь с примером?
Hello.
Is it possible to run 2 websocket servers on 1 VDS?
I have 2 web applications on 1 VDS. Both of them use your yii2 websocket extension.
To start the 1st websocket server I run:
cd /var/www/app1
./yii websocket/start notificationServer1
But when I run the 2nd websocket server:
cd /var/www/app2
./yii websocket/start notificationServer2
then I get "already started" in the console output. I want the 2nd server working as well.
How can I make it work?
config1:
'websocket' => [ 'class' => 'morozovsk\yii2websocket\Connection', 'servers' => [ 'notificationServer1' => [ 'class' => 'app\modules\v1\modules\notification\components\WebsocketDaemonHandler', 'pid' => '/tmp/websocket_chat.pid', 'websocket' => 'tcp://127.0.0.1:8004', 'localsocket' => 'tcp://127.0.0.1:8010' ] ], ],
config2:
'websocket' => [ 'class' => 'morozovsk\yii2websocket\Connection', 'servers' => [ 'notificationServer1' => [ 'class' => 'app\modules\v1\modules\notification\components\WebsocketDaemonHandler', 'pid' => '/tmp/websocket_chat.pid', 'websocket' => 'tcp://127.0.0.1:8014', 'localsocket' => 'tcp://127.0.0.1:8024' ] ], ],
Hope you got what I mean. Thanks in advance.
У меня при соединении по некоторым клиентам будет осуществляться рассылка больших объемов данных, как сделать чтоб они не блокировали работу остальных клиентов?
Прикручивать pthreads?
Possible logic error
I did not actually run your code but from looking at it..
And I might be wrong because i really do not understand the Russian language, in that case i apologize..
Here goes..
Daemon.php
protected function _onOpen($connectionId) {
$this->_handshakes[$connectionId] = '';//отмечаем, что нужно сделать рукопожатие
}
protected function _onMessage($connectionId) {
if (isset($this->_handshakes[$connectionId])) {
if ($this->_handshakes[$connectionId]) {//если уже было получено рукопожатие от клиента
return;//то до отправки ответа от сервера читать здесь пока ничего не надо
}
if (!$this->_handshake($connectionId)) {
$this->close($connectionId);
}
} else {
while (($data = $this->_decode($connectionId)) && mb_check_encoding($data['payload'], 'utf-8')) {//декодируем буфер (в нём может быть несколько сообщений)
$this->onMessage($connectionId, $data['payload'], $data['type']);//вызываем пользовательский сценарий
}
}
}
The above 2 methods are called from the while
loop GenericSelect->start()
in GenericSelect.php
.
...
if ($this->_handshakes[$connectionId]) {//если уже было получено рукопожатие от клиента
return;//то до отправки ответа от сервера читать здесь пока ничего не надо
}
...
The $this->_handshakes[$connectionId]
contains an empty string ('') which evaluates to true
.
This causes the function to return
and actual handshake $this->_handshake($connectionId)
to never happen..
You probably meant to check for:
...
if ($this->_handshake($connectionId)) {//если уже было получено рукопожатие от клиента
return;//то до отправки ответа от сервера читать здесь пока ничего не надо
}
...
That would evaluate to true
on an incomplete handshake and return
to continue reading until a complete handshake has been received..
Websocket standards
Daemon.php
protected function _onMessage($connectionId) {
...
if (!$this->_handshake($connectionId)) {
$this->close($connectionId);
}
...
}
The connection simply gets closed while the websocket standard states that a proper response should be written to the client.
For example when the handshake does not contain Sec-WebSocket-Key
the proper response to write to the client would be "HTTP/1.1 400 Bad Request\r\n\r\n"
In fact the handshake should be checked for many more errors for example when Sec-WebSocket-Version
is incompatible the proper response to write to the client would be "HTTP/1.1 426 Upgrade Required\r\nSec-WebSocketVersion: 13\r\n\r\n"
A possible solution would be to:
Daemon.php
protected function _onMessage($connectionId) {
if (isset($this->_handshakes[$connectionId])) {
if ($this->_handshake($connectionId)) {//если уже было получено рукопожатие от клиента
return;//то до отправки ответа от сервера читать здесь пока ничего не надо
}
if ($this->_handshakes[$connectionId] != false && !$this->_handshake($connectionId)) {
$this->_handshakes[$connectionId] = false;
}
} else {
while (($data = $this->_decode($connectionId)) && mb_check_encoding($data['payload'], 'utf-8')) {//декодируем буфер (в нём может быть несколько сообщений)
$this->onMessage($connectionId, $data['payload'], $data['type']);//вызываем пользовательский сценарий
}
}
}
Do not call $this->close($connectionId)
strait away but set $this->_handshakes[$connectionId]
to false
.
GenericSelect.php
...
if ($write) {
foreach ($write as $client) {
if (is_resource($client)) {//проверяем, что мы его ещё не закрыли во время чтения
$this->_sendBuffer($client);
if ($this->_handshakes[$client] == false) { $this->close($client); }
}
}
}
...
On the next while
loop stream_select($read, $write, $except, null);
will pick up the _write
buffer containing the error and once it has written the proper response check $this->_handshakes[$client]
for false
and close the connection there..
That's what i've found so far..
I like your coding style, keep up the good work!
Hello. Thank you for this great library
I have a website using HTTPS. And I can not connect to websocket server via WS protocol. I need WSS instead. How can I do it with your library?
Здравствуйте.
Такой вопрос не тривиальный.
Сколько у вас ушло времени на создание рабочего прототипа и примеров с третьим чатом?
Спасибо.
if ( $this->timer && in_array( $timer, $read ) ) {
unset( $read[ array_search( $timer, $read ) ] );
fread( $timer, self::SOCKET_BUFFER_SIZE );
$this->onTimer();
}
I see the error:
PHP Error[8]: fwrite(): send of 1 bytes failed with errno=32 Broken pipe
It is in the code:
else { //дочерний процесс
fclose( $pair[ 1 ] );
$parent = $pair[ 0 ]; //второй в дочернем процессе
while ( true ) {
fwrite( $parent, '1' );
usleep( $this->timer * 1000000 );
}
}
Also parent process wasn't closed. In process manager I see that child process has closed, but parent process is not. And I see two PHP processes per worker. It is ok?
First of all thanks for the amazing code. Especially the websocket chat for private messaging.
So this issue was already posted at #9 but since there is still no answer, I will post this issue again.
I really like to use and study the script but I am using windows 7 64 bit with PHP 5.6, and since the "posix" functions of PHP like "posix_getpid" doesn't work on windows, I can't use it.
Is there any alternative PHP functions for posix or could you update the chat3 demo so I can use it under Windows?
class Websocket extends CApplicationComponent
{
public $woker = array(
'socket' => 'tcp://127.0.0.1:8002',
'class' => 'GameWebsocketWorkerHandler',
'timer' => 0.1
);
Right: $worker instead of $woker )
Здравствуйте.
Использую примеры Chat3.
Только userId формирую из своих даных.
Случается так, что нужно продублировать вкладку, хотя бы просто что бы запомнить выдачу, а другую обновить и сравнить результат.
Итого одна и та же страница , одни и те же данные для формирования userId и два коннекта по сокету.
Подскажите пожалуйста, можно ли не создавать новые соединение, а вернуть имеющееся, если совпадает userId?
Возможно ответ и есть в коде, но вы свой код знаете лучше, не поймите не правильно.
Спасибо.
hi, I'm sorry to open ticket for my question , but actually I'm not pro in php and with your instruction not figure out how to install it in my remote directory host , and really appreciate for couple of hints , in fact I've tried to hook url on my host to the Telegram webhoock call back bot, so at first step new update data inserted to MySQL database then websoket server give the update data to designated live client .
can you tell me which files should be copy in designated host URL and what files should be modified?
Thanks
Здравствуйте.
Большое спасибо за проект, разбираюсь и интегрирую.
Передо мной встала задача ловить pg_get_notify(), поразбиравшись в примерах я решил использовать метод onTimer(). Насколько я понял, принцип работы заключается в запуске дочернего процесса, который через заданный интервал выполняет заданные действия. Судя по всему это то, что надо, однако есть небольшая проблема.
Дело в том, что при выполнении команды ./yii websocket/stop
сервер корректно завершает работу, а вот дочерний процесс похоже остается, и поэтому в консоль выводится ошибка:
PHP Notice 'yii\base\ErrorException' with message 'fwrite(): send of 1 bytes failed with errno=32 Broken pipe'
in /var/www/project.zz/vendor/morozovsk/websocket/GenericSelect.php:188
Или я ошибаюсь? Это, в принципе, не критично, но есть желание сделать все корректно.
Спасибо.
Добрый день! В первую очередь хотел выразить слова благодарности Вам за вашу библиотеку, используем в боевых условиях, очень круто!
По мере роста проекта уперлись конечно же в ограничение 1024 коннекта. Переписываем на вариант с воркерами, и тут возникает такой вопрос: а чем/как можно все это дело протестировать? В самой первой вашей статье на хабре Вы писали, что локально подавали одновременно 10к соединений, хотелось бы протестировать также работу с воркерами.
Добрый день!
Спасибо за вашу библиотеку.
Подскажите пожалуйста, при использовании библиотеки, довольно часто возникает ошибка:
Notice: fwrite(): send of 1024 bytes failed with errno=32 Broken pipe
Может ли это связано с тем, что я увеличил MAX_SOCKET_BUFFER_SIZE до 262144 ?
И еще, простите за столь нубский вопрос, для чего нужны 'localsocket' => и 'master' =>, в чем отличие от 'websocket' => ?
Спасибо.
Здравствуйте
Можете подсказать, как можно передать изображение из браузера через вебсокет именно как файл (бинарник) и как принять правильно это файл на стороне сервера?
Hello.
My OS is windows 7 -> php 7.1
i have one issue with request/response. I use GenericSelect class.
Example:
send requests to server
1 - task:'login' ... (take 10 seconds) sent time - 00:00:00
2 - task:'event'.... (take 1 second) sent time - 00:00:01
This is response
1 - task:'login' ... time - 00:00:10
2 - task:'event'.... time - 00:00:10
but i would have this respone
1 - task:'event' ... time - 00:00:01
2 - task:'login'.... time - 00:00:10
Could anybody help me solving this issue? I tried to use timer but unfortunately o had an error inside _createTimer function
Thanks
Проблема в том, что читается один раз до SOCKET_BUFFER_SIZE байт. Если в буфере байт больше, повторно onRead не вызовется и соединение "зависнет".
Лечится заменой в GenericEvent функции _read на такую:
protected function _read($connectionId)
{
while (true)
{
$data = $this->buffers[$connectionId]->read(self::SOCKET_BUFFER_SIZE);
if (!strlen($data)) break;
@$this->_read[$connectionId] .= $data; //add the data into the read buffer
}
return strlen($this->_read[$connectionId]) < self::MAX_SOCKET_BUFFER_SIZE;
}
Если пакет превышает значение константы SOCKET_BUFFER_SIZE, то он не считывает следующую часть, а ждет повторного срабатывания события onRead.
При переезде на https получаю timeout, клиент соединяется через wss://
Добрый день. Не поможете советом?
Есть небольшая проблема. Может быть, Вы с подобным уже сталкивались, и мне не придётся заново изобретать велосипед.
Всё установил, запустил, даже подключился. Но есть одно но, сообщения на клиент приходят через раз и какие-то обрезанные. Причём после отдачи этого обрезанного сообщения падает соединение с сервером. Клиент есть здесь: http://boroviha.dev.ooosis.com/example/index.html
В Вашем коде практически ничего не менял, только в методе ChatWebsocketDaemonHandler::onOpen убрал второй параметр.
Возможно это так и задумано, но если на сайте делать ws.close то происходит событие onMessage с $type=="close", а событие onClose происходит только после того как сайт прерывает соединение (наверно по тайм ауту).
При запуске с помощью nohup:
nohup index.php start &
Команды
php index.php stop
php index.php restart
не приводят к ожидаемому результату.
Процессы продолжают висеть...
Could you please provide instuction for a websocket server to show in a log windows messages sent from different clients with their IP and sending message to each of clients with http or www domain name.TQ
Добрый день. У вас заявлена поддерживаемая нагрузка в 100 000 соединений, у вас есть результаты нагрузочного тестирования или хотя бы примерные сведенья о расходе памяти и CPU на каждое соеденение?
Здравствуйте.
Использую https://github.com/morozovsk/websocket-examples/tree/master/chat3
Нужно получить список пользователей через PHP.
Взял текущий файл: https://github.com/morozovsk/websocket-examples/blob/master/chat3/server/send.php
И постарался самостоятельно состряпать, что то вроде:
#!/usr/bin/env php
<?php
$socketUrl = 'tcp://127.0.0.1:8010';
$message = "message";
$userId = "k4krmk4k3";
$context = stream_context_create();
$instance = stream_socket_client($socketUrl, $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context);
if( !$instance ) echo "$errstr ($errno)<br />\n";
else
{
$sent = fwrite( $instance, json_encode( ['message' => $message, 'userId' => $userId] )."\n");
if( $sent > 0 )
{
$server_response = fread($instance, 4096);
echo $server_response;
}
}
В данном файле https://github.com/morozovsk/websocket-examples/blob/master/chat3/server/Chat3WebsocketDaemonHandler.php в методе onOpen я добавил условие, и получил такое:
protected function onOpen($connectionId, $info) /// Вызывается при соединении с новым клиентом
{
///$message = 'пользователь #' . $connectionId . ' : ' . var_export($info, true) . ' ' . stream_socket_get_name($this->clients[$connectionId], true);
///foreach( $this->clients as $clientId => $client ) $this->sendToClient($clientId, $message);
$info['GET']; /// or use $info['Cookie'] for use PHPSESSID or $info['X-Real-IP'] if you use proxy-server like nginx
parse_str(substr($info['GET'], 1), $_GET);//parse get-query
///var_export($_GET['id']);
$userId = @$_GET['userId'];
$this->userIds[$connectionId] = $userId;
if( 'k4krmk4k3'==$userId )
{
$message = json_encode(array(
'clients'=>$this->userIds,
'info'=>$info,
));
$this->sendToClient($connectionId, $message);
}
}
Через вашего клиента на JS, все гуд, но нужно через PHP.
Конечно на это все не знание и не понимание, но в первую очередь решил обратиться к вам.
Надеюсь поможете с этим вопросом.
Спасибо.
Периодически возникает ошибка PHP Error[2]: stream_select(): supplied argument is not a valid stream resource
in file /var/www/ph2/protected/extensions/websocket/GenericSelect.php at line 63
#0 /var/www/ph2/protected/extensions/websocket/GenericSelect.php(63): stream_select()
#1 /var/www/ph2/protected/extensions/websocket/Server.php(84): morozovsk\websocket\Chat3WebsocketDaemonHandler->start()
С чем может быть связано?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.