Настройка WebSocket на сайте для быстрого обмена данными
Доброго времени друзья! Вкратце решил описать как организовать обмен данными клиент-сервер, на базе протокола WebSocket, в рамках сайта, например для мгновенного обмена сообщениями в чате. Принцип работы следующий — запускаем скрипт на PHP, работающий в фоновом режиме(это сервер WS), вешаем его на порт(например на 8090), далее настраиваем проксирование Apache или nGinx, чтобы все запросы из вне, по протоколу WS(с HTTP заголовком Upgrate: websocket) переправлялись на localhost:8090. Затем подключаемся к серверу из JavaScript, слушаем и обрабатываем данные. Отправляем сообщения в сокет из PHP. Собственно всё. Далее подробно.
Скрипт на PHP
Пример скрипта на PHP, который выступает в роли сервера WebSocket, сам скрипт я разбирать не буду, там достаточно все просто(работает на основе PHP расширения Socket), но если что-то не понятно, будет повод разобраться.
<?php $sServer = new socketServer(); $sServer->host = 'localhost'; $sServer->patch = 'server.php'; $sServer->port = 8090; $sServer->init(); class socketServer{ public $host; public $patch; public $port; private $socket; private $clients; function __construct(){ $this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); } public function init(){ socket_set_option( $this->socket, SOL_SOCKET, SO_REUSEADDR, 1 ); socket_bind( $this->socket, 0, $this->port ); socket_listen( $this->socket ); $this->clients = [ $this->socket ]; while( true ){ $null = []; $nSockets = $this->clients; socket_select( $nSockets, $null, $null, 0, 10 ); if( in_array( $this->socket, $nSockets ) ){ $nSocket = socket_accept( $this->socket ); $headers = socket_read( $nSocket, 1024 ); $this->clients[] = $nSocket; $this->headers( $headers, $nSocket ); unset( $nSockets[ array_search( $this->socket, $nSockets ) ] ); } foreach( $nSockets as $nsData ){ while( @ socket_recv( $nsData, $sData, 1024, 0 ) >= 1 ){ $socketMessage = $this->decode( $sData ); if( $args = json_decode( $socketMessage, true ) ) $this->send( $args, $this->clients ); break 2; } $sData = @ socket_read( $nsData, 1024, PHP_NORMAL_READ ); if( $sData === false ){ unset( $this->clients[ array_search( $nsData, $this->clients ) ] ); } } } } private function headers( $headersStr, $socket ){ $headers = []; $headersStr = preg_split("/\r\n/", $headersStr); foreach( $headersStr as $hStr ){ $hStr = rtrim( $hStr ); if( preg_match('/\A(\S+): (.*)\z/', $hStr, $match ) ) $headers[ $match[1] ] = $match[2]; } $key = base64_encode( pack('H*', sha1( $headers['Sec-WebSocket-Key'] .'258EAFA5-E914-47DA-95CA-C5AB0DC85B11' ) ) ); $header = "HTTP/1.1 101 Switching Protocols \r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "WebSocket-Origin: $this->host" . "WebSocket-Location: ws://$this->host:$this->port$this->patch\r\n" . "Sec-WebSocket-Accept: $key\r\n\r\n"; socket_write( $socket, $header, strlen( $header ) ); } private function send( $args ){ $args = array_merge( $args, [ 'time' => date('H:i') ] ); $msg = $this->encode( json_encode( $args ) ); $length = strlen( $msg ); foreach( $this->clients as $client ) @socket_write( $client, $msg, $length ); return true; } private function encode( $sData ){ $b = 0x81; $header = ''; $length = strlen( $sData ); if( $length <= 125 ) $header = pack( 'CC', $b, $length ); elseif( $length > 125 && $length < 65536 ) $header = pack( 'CCn', $b, 126, $length ); elseif( $length > 65536 ) $header = pack( 'CCNN', $b, 127, $length ); return $header . $sData; } private function decode( $sData ){ $str = ''; $length = ord( $sData[1] ) & 127; if( $length == 126 ){ $mask = substr( $sData, 4, 4 ); $data = substr( $sData, 8 ); } elseif( $length == 127 ){ $mask = substr( $sData, 10, 4 ); $data = substr( $sData, 14 ); } else { $mask = substr( $sData, 2, 4 ); $data = substr( $sData, 6 ); } for( $i=0; $i < strlen( $data ); $i++ ) $str .= $data[ $i ] ^ $mask[ $i%4 ]; return $str; } function __destruct(){ socket_close( $this->socket ); } }?> |
Запускаем демон на PHP (сервер WS)
Скрипт запускается в режиме демона, командой:
php server.php & |
Настраиваем проксирование Apache на сервер WS
Чтобы все запросы, пришедшие на наш сайт, такого вида https://example.com/socket/ по протоколу WS/WSS, перенаправлялись на WebSocket сервер, что слушает порт 8090, в настройка Apache, добавляем следующее:
RewriteEngine On RewriteCond %{HTTP:Upgrade} =websocket [NC] RewriteRule /socket/ ws://localhost:8090 [P,L] |
Если у вас на сервере стоит связка nGing и Apache, то проксирование можно настроить только на nGinx.
Отправляем сообщение в WebSocket из PHP
Отправляем сообщения на WebSocket, из PHP(используя Stream) по протоколу HTTPS:
<php $args = []; // Массив с отправляемыми данными $port = 443; $host = 'example.com'; $headers = "GET /socket/ HTTP/1.1\r\n" . "Host: $host\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Key: " . base64_encode( random_bytes( 16 ) ) . "\r\n" . "Sec-WebSocket-Version: 13\r\n\r\n"; $context = stream_context_create( [ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false ] ] ); $socket = stream_socket_client("ssl://$host:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context); if( $socket ){ fwrite( $socket, $headers ); $response = fread( $socket, 1024); fwrite( $socket, $this->wsEncode( json_encode( $args ) ) ); fclose( $socket ); } |
Подключаем скрипт на JavaScript к WS
Прослушиваем WebSocket на стороне сайта из JavaScript:
var socket = new WebSocket('wss://example.com/socket/'), app.socket.onopen = () => {}; app.socket.onclose = () => {}; app.socket.onerror = error => {}; app.socket.onmessage = function(event) { var data = JSON.parse( event.data ); // Обработка пришедших сообщений }; |
Друзья, если вам нужна можешь в настройке WebSocket на вашем сайте, обращайтесь, буду раз сотрудничеству!
Похожие записи
Оставить комментарий
Full Stack
Senior, Architect
предложить оффер
- jQuery: как получить значение атрибута?
- PHP работа с изображением, класс SimpleImage
- Интеграция с API ОСАГО сайта sravni.ru
- Комментарии на PHP, Ajax, mySQL
- PHP: Категории бесконечного уровня вложенности.
- Nginx редирект на другой сервис с сохранением URL спросил (а) Сергей
- Исполнитель пропал, почему такое случается и понять с кем работать? спросил (а) Артем
- Можно ли WordPress считать универсальным движком? спросил (а) Андрей
- Что такое самописный скрипт или CMS? спросил (а) Антон
- Как при поиске в linux используя grep, добавить исключения? спросил (а) Алексей
- Консольный скрипт(JavaScript) для автоматических заказов на OZON к записи
- Консольный скрипт(JavaScript) для автоматических заказов на OZON к записи
- Как создать Telegram-бота с авторизацией через сайт к записи
- PHP скрипт: каталог закладок на сайты к записи
- Валидация на PHP к записи
- Сколько зарабатывают в бизнесе на совместных покупках к записи
- Сколько зарабатывают в бизнесе на совместных покупках к записи
Archive
- +2024 (29)
- Декабрь 2024 (1)
- Ноябрь 2024 (13)
- Октябрь 2024 (8)
- Сентябрь 2024 (1)
- Август 2024 (5)
- Май 2024 (1)
- +2023 (27)
- Ноябрь 2023 (1)
- Октябрь 2023 (13)
- Сентябрь 2023 (10)
- Апрель 2023 (1)
- Март 2023 (1)
- Февраль 2023 (1)
- +2022 (21)
- Декабрь 2022 (11)
- Ноябрь 2022 (1)
- Май 2022 (2)
- Апрель 2022 (2)
- Март 2022 (3)
- Февраль 2022 (1)
- Январь 2022 (1)
- +2021 (17)
- Декабрь 2021 (5)
- Ноябрь 2021 (2)
- Июль 2021 (1)
- Июнь 2021 (2)
- Май 2021 (5)
- Апрель 2021 (1)
- Март 2021 (1)
- +2020 (20)
- Декабрь 2020 (6)
- Сентябрь 2020 (2)
- Август 2020 (1)
- Июль 2020 (2)
- Май 2020 (2)
- Апрель 2020 (2)
- Март 2020 (2)
- Февраль 2020 (1)
- Январь 2020 (2)
- +2019 (18)
- Декабрь 2019 (3)
- Ноябрь 2019 (2)
- Октябрь 2019 (2)
- Сентябрь 2019 (1)
- Август 2019 (2)
- Июль 2019 (1)
- Июнь 2019 (1)
- Апрель 2019 (2)
- Март 2019 (1)
- Февраль 2019 (3)
- +2018 (44)
- Декабрь 2018 (4)
- Ноябрь 2018 (7)
- Октябрь 2018 (8)
- Сентябрь 2018 (1)
- Август 2018 (4)
- Июль 2018 (5)
- Май 2018 (3)
- Апрель 2018 (7)
- Март 2018 (1)
- Февраль 2018 (2)
- Январь 2018 (2)
- +2017 (19)
- Декабрь 2017 (2)
- Ноябрь 2017 (1)
- Октябрь 2017 (1)
- Сентябрь 2017 (2)
- Июль 2017 (1)
- Июнь 2017 (1)
- Май 2017 (2)
- Апрель 2017 (3)
- Март 2017 (2)
- Февраль 2017 (1)
- Январь 2017 (3)
- +2016 (36)
- Декабрь 2016 (3)
- Ноябрь 2016 (3)
- Октябрь 2016 (2)
- Сентябрь 2016 (3)
- Август 2016 (7)
- Июнь 2016 (3)
- Май 2016 (3)
- Апрель 2016 (3)
- Февраль 2016 (1)
- Январь 2016 (8)
- +2015 (36)
- Ноябрь 2015 (5)
- Октябрь 2015 (4)
- Сентябрь 2015 (1)
- Август 2015 (8)
- Июнь 2015 (1)
- Май 2015 (4)
- Апрель 2015 (8)
- Март 2015 (3)
- Февраль 2015 (2)
- +2014 (26)
- Ноябрь 2014 (2)
- Октябрь 2014 (5)
- Сентябрь 2014 (6)
- Июль 2014 (1)
- Июнь 2014 (2)
- Май 2014 (3)
- Апрель 2014 (6)
- Февраль 2014 (1)
- +2013 (27)
- Декабрь 2013 (2)
- Ноябрь 2013 (1)
- Октябрь 2013 (1)
- Август 2013 (1)
- Июль 2013 (3)
- Июнь 2013 (10)
- Май 2013 (1)
- Апрель 2013 (2)
- Февраль 2013 (3)
- Январь 2013 (3)
- +2012 (41)
- Декабрь 2012 (2)
- Ноябрь 2012 (3)
- Октябрь 2012 (7)
- Сентябрь 2012 (2)
- Август 2012 (1)
- Июль 2012 (3)
- Июнь 2012 (2)
- Май 2012 (6)
- Апрель 2012 (2)
- Март 2012 (7)
- Февраль 2012 (5)
- Январь 2012 (1)
- +2011 (57)
- Декабрь 2011 (6)
- Ноябрь 2011 (2)
- Октябрь 2011 (3)
- Сентябрь 2011 (5)
- Август 2011 (4)
- Июль 2011 (3)
- Июнь 2011 (3)
- Май 2011 (3)
- Апрель 2011 (4)
- Март 2011 (10)
- Февраль 2011 (5)
- Январь 2011 (9)
- +2010 (43)
- Декабрь 2010 (7)
- Ноябрь 2010 (21)
- Октябрь 2010 (14)
- Сентябрь 2010 (1)
Свежие записи
- Прокси веб-сервера Apache и nGinx 03.12.2024
- Настройка WebSocket на сайте для быстрого обмена данными 30.11.2024
- Подключение сайта к доставке DPD по API 28.11.2024
- Бот для автоматических заказов на Wildberries 22.11.2024
- Интеграция платежной системы MoonPay на сайт по API 10.11.2024