Компютри Windows интернет

javascript сокети и php сървър. Сокети в PHP. Използване на WebSocket с phpws. Кога да избягвате използването на WebSockets

Или да започнете с WebSocket PHP без phpDaemon

Здравейте! Съжалявам за толкова дългото заглавие, но се надявам, че тази статия ще бъде по-лесна за намиране от начинаещи като мен, защото аз не можах да намеря нищо подобно. Преди няколко седмици реших да преработя клиента на играта и сървъра на моята игра Growing Crystals с AJAX, на WebSocket, но всичко се оказа не само трудно, но и много трудно. Ето защо реших да напиша статия, която ще помогне на най-начинаещите разработчици на WebSocket + PHP да спестят няколко дни време, като обясня възможно най-подробно всяка стъпка в настройката и стартирането на първия WebSocket скрипт в PHP.

Няма да предоставя кода за сокет сървъра в PHP, защото... той е в архива и е снабден с коментари. Изкуствено ограничих работното време за приемане на връзки до 100 секунди, така че скриптът да не остава в паметта, да затваря всички връзки и да не се налага непрекъснато да рестартирате Denver, когато правите промени в него. Освен това след 100 секунди скриптът няма да спре да работи, а ще изчака връзка, след което работата му ще приключи и всички сокети ще бъдат безопасно затворени. Освен това за тестване използвам localhost и порт 889.

Socket_bind($socket, "127.0.0.1", 889);//свържете го към указания ip и порт

Файловете от архива могат да бъдат поставени в главната папка localhost на Denver. Алгоритъм за тестване:

  1. Стартираме http://localhost/socket.html, той автоматично ще се свърже с ws echo сървъра ws://echo.websocket.org, можете да изпратите няколко съобщения, които сървърът трябва да изпрати обратно, защото това е echo сървър. Ако работи, страхотно, всичко е наред с клиента, ако не, проверете дали сте поставили всички файлове в една директория, дали работи Denver и дали имате интернет връзка.
  2. Отворете JavaScript конзолата в същия раздел, където имате отворен ws клиент (В GoogleChrome 34.8.1847.137 m и във FireFox това се прави почти по същия начин меню->инструменти->Java Script конзола или Ctrl+Shift+J, но лично аз използвайте за тази конзола на FireBug). Изпратете още няколко съобщения. Ще видите какви съобщения идват от сървъра. Можете да щракнете върху прекъсване на връзката и след това да изпратите няколко съобщения, ще се уверите, че съобщенията няма да изчезнат, защото. връзката със сървъра ws://echo.websocket.org е прекъсната.
  3. Стартираме нашия сокет сървър http://localhost/simpleworking.php в нов раздел на браузъра. Желателно е веднага да видите както клиентския раздел с конзолата, така и сървърния раздел. GO() ... socket_create ... OK socket_bind ... OK Слушащ сокет... OK

    Което означава, че сървърът е готов за входящи връзки.

  4. В раздела клиент, в полето Адрес на сървъра, въведете ws://127.0.0.1:889 и щракнете върху повторно свързване, виждаме, че нищо не се случва на клиента, но съобщения като Клиент „Идентификационен номер на ресурс #3“ се е свързал Изпрати до клиент " Здравейте" се появи на сървъра, Клиент!"... ОК Чака се... ОК

    Което ни казва, че технически е установена връзка към сокета на сървъра, но се очаква връзка през протокола на уеб сокета на клиента и тя не е установена, т.к. Браузърът не получи подходящите хедъри на ws протокола. Когато се опитате да изпратите съобщение от клиента, трябва да се появи грешка в конзолата, че връзката към ws не е установена. За съжаление, скриптът в GoolgeChrome ще спре и за нови опити за свързване ще трябва да презаредите страницата с уеб клиента. Във FireFox скриптът продължава да се изпълнява. Не забравяйте да се свържете отново 100 секунди след стартиране на сървърния скрипт, за да може да завърши успешно.

    Клиентът "Resource id #4" се свърза Изпрати до клиента "Hello, Client!"... OK time = 309.8900001049return go() ended Затваряне на връзката... OK

  5. За да се уверите най-накрая, че сървърът отговаря и че неговите съобщения не са блокирани от защитната стена, стартирайте сървърния скрипт http://localhost/simpleworking.php, стартирайте telnet и опитайте да се свържете към 127.0.0.1:889, но това трябва да е направено не по-късно от 100 секунди, от момента на стартиране на сървъра до затварянето на връзките и завършването на скрипта.

Отговорът “Hello, Client!” трябва да дойде по telnet, което показва, че всичко работи нормално и връзката със сървъра е двупосочна.

Когато тествате на локален компютър с помощта на Denver, винаги се уверявайте, че PHP скриптът е завършен, в противен случай рестартирайте Denver, за да избегнете сблъсъци и заети портове.

Websocket протокол

Сега всичко, което остава, е да научим нашия сокет сървър да комуникира като уеб сокет сървър, да работи правилно във фонов режим (демон) и, най-важното, на евтин хостинг. Малко теория: позволяваме на сървъра да показва съобщението, което получаваме от клиента, когато се опитваме да се свържем, добавяйки $msg = „Здравей, Клиент!“ преди реда; код

Echo „Клиент \"".$accept."\" казва:

";
ехо socket_read($accept,512);
ехо "
";

Можете да видите, че опитът за установяване на връзка с помощта на протокола WebSocket винаги е придружен от клиента, изпращащ заглавка в задължително съответствие с формата на протокола WebSocket. Предварителният етикет за показване на заглавки не е избран случайно, т.к В заглавията, новият ред играе голяма роля. Това са заглавките, които получавам от браузърите, когато се опитвам да се свържа с нашия ws://127.0.0.1:889.

GET / HTTP/1.1 Хост: localhost:889 Потребителски агент: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0 Приемане: text/html,application/xhtml+xml,application/xml; q=0.9,*/*;q=0.8 Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Sec-WebSocket-Version : 13 Произход: http://localhost Sec-WebSocket-Key: ndHtpnSPk2H0qOeP6ry46A== Бисквитка: vc=3; __gads=ID=9eabc58c385071c7:T=1400699204:S=ALNI_Ma_g9PZBXpi_MLKDBsao3LQiGx-EA Връзка: поддържане, Прагма за надграждане:

GET / HTTP/1.1 Надстройка: websocket Връзка: Надстройка Хост: localhost:889 Произход: http://localhost Pragma: no-cache Cache-Control: no-cache Sec-WebSocket-Key: zNMTfmc+C9UK6Ztmv4cE5g== Sec-WebSocket- Версия: 13 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame Потребителски агент: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, като Gecko) Chrome/35.0.1916.114 Safari/537.36

Дори преди да започна да изучавам уеб сокети, мислех, че работата с уеб сокети ще бъде подобна на работата с AJAX, където изпращахме заявки към сървъра, използвайки JavaScript XMLHttpRequest(), но в действителност задачата се оказа много по-сложна и първо, защото WebSocket е протокол на същото ниво като HTTP протокола (но с някои нюанси) в OSI мрежовия модел, което означава, че от страната на сървъра трябва да внедрим функционалност, подобна на HTTP обработката (което Apache винаги е правил ). Продължавайки сравненията с AJAX, в AJAX не е необходимо да предоставяме HTTP протокола, защото Всичко това се прави от браузъра Apache и уеб сървъра. Ние просто изпращаме и получаваме съобщения. Но въпреки че използването на ws ни налага доста голяма работа, свързана с внедряването на сървър в PHP, то също така предоставя предимства: намаляване на количеството прехвърляни данни и увеличаване на производителността на сървърния софтуер. За да комуникира успешно с клиенти по протокола WebSocket, сървърът трябва стриктно да отговаря на изискванията на стандарта RFC6455, който описва подробно форматите на заглавките на отговорите. Всички съобщения, изпратени чрез протокола WebSocket, могат да бъдат разделени на няколко вида: handsnake (ръкостискане при установяване на връзка), ping-pong (проверка на връзката) и data-transfer (пренос на данни). Има и по-кратко описание на протокола в общи линии на руски език. За да се осигури пълна, коректна комуникация между сървъра и клиента чрез протокола за уеб сокет, е необходимо да се внедрят функции в PHP за получаване и анализиране на хедъри от клиента, компилиране на хедъри от сървъра, компилиране на ключ и номер от другите. След като проучихме материалите, представени на Habré и ​​други ресурси, успяхме да намерим внедрени подходящи функции, единствената объркваща разлика беше, че повечето автори използват поточни функции за работа със сокети, те се считат за по-компактни, но в същото време по-ресурсоемки поради използването на буфер. За да преминете към поточни функции за работа със сокети, не е необходимо да инсталирате допълнителни модули, освен вече инсталираните, т.к. нишките са вградени в PHP 5 по подразбиране. Функциите на потоковия сокет винаги започват с stream_socket_*. Когато използвате функции за поток, препоръчително е да се уверите, че phpinfo() поддържа необходимия транспорт за потоци.

Регистрирани транспорти на поточен сокет: tcp, udp.

Ако няма такава информация в phpinfo() или ако възникнат други проблеми, моля, вижте документацията, но проблемът може да бъде решен чрез просто актуализиране на Denver до текущата версия.
Друг важен факт е, че повечето системи ограничават възможността за създаване на сокет на порт по-нисък от 1024, така че във всички следващи програми за сокет ще се използва порт 8889.
Вземайки изходните кодове на функциите за кодиране и декодиране на заглавките на протокола WebSocket като основа, успяхме да внедрим пълноценен ws echo сървър. Алгоритъмът за неговата работа е толкова прост, колкото и в предишния случай: създаваме ws сървър с помощта на функцията stream_socket_server, изпълняваме безкраен цикъл, в който проверяваме за нови връзки и когато получим нова връзка, я поставяме в $connects масив, също стартирайте втори цикъл, който преминава през всички връзки и затваря неуспешните и получава съобщения от отворени връзки. Също така добавих три функции към PHP скрипта, които проектирах като манипулатори на събития.

Функция onOpen($connect, $info) (
ехо "отвори OK
\н";
}

функция onClose($connect) (
ехо "затвори OK
\н";
}

функция onMessage($connect, $data) (
$f = декодиране ($данни);
echo "Съобщение:";
ехо $f["полезен товар"] . "
\н";
fwrite($connect, encode($f["payload"]));
}

Които не правят нищо, освен да показват съобщения за събития на екрана. И когато получим съобщение от клиента, ние го декодираме и изпращаме текста му, като предварително сме го кодирали, обратно. , ws клиентът не е променен. Можете да тествате ws echo сървъра, като изтеглите архива и го поставите в главната папка на локалния хост на Denver. Свържете клиента към адреса ws://127.0.0.1:8889.
Ще обсъдим тънкостите, свързани с работата на ws сървър във фонов режим (демон) и стартирането му на хостинг. Ще се радвам на коментари и отзиви.

Особено за тези, които търсят хостинг за стартиране на вашия проект на уеб сокетидискусия

Моите статии за PHP демони и уебсокети

  • Прост уеб сокет в PHP или уеб сокети с абсолютна 0

Уебсокети

Сървърните събития, обсъдени по-рано, са идеален инструмент, когато трябва да получите поредица от съобщения от уеб сървър. Но връзката се оказва напълно едностранчива. Браузърът не може да отговаря на съобщения или да участва в по-сложен диалог със сървъра.

Ако създавате уеб приложение, което изисква значителна двупосочна комуникация между браузъра и уеб сървъра, най-добрият подход за внедряването му (без да прибягвате до Flash) вероятно е да използвате XMLHttpRequest обект. В зависимост от вида на приложението, което създавате, този подход може да работи по желание. Но тук има доста възможни проблеми.

Първо, обектът XMLHttpRequest не е много подходящ за бърз обмен на множество съобщения (например в чат). Тогава няма начин да се свърже едно обаждане с друго, така че с всяка нова заявка от уеб страница сървърът трябва да разбере от самото начало на кого принадлежи тази страница. Следователно нивото на сложност на кода за обработка на поредица от свързани заявки от уеб страница може много бързо да нарасне до точката, в която е практически невъзможно да се приложи.

За всички тези проблеми има решение, макар и то да не е съвсем готово. Това решение е технология уеб сокети, което позволява на браузъра да поддържа отворена връзка със сървъра и да обменя съобщения за необходимото време.

Технологията Websocket предизвика много вълнение сред уеб разработчиците, но все още е в процес на разработка, въпреки че вече има добра съвместимост с браузър:

Засега е най-добре да тествате страници, които използват websockets в браузъра Chrome, който осигурява най-последователната поддръжка за тях.

Достъп до websockets

Websockets са специализиран инструмент. Те са от значение за приложения като чат, масивни мултиплейър игри или инструмент за комуникация между партньори. Websockets ви позволяват да създавате нови типове приложения, но те вероятно нямат смисъл в повечето съвременни уеб приложения, управлявани от JavaScript.

Websocket решенията могат да бъдат изключително сложни. Разработването на JavaScript код за една страница ще бъде доста проста задача. Но за да създадете сървърно приложение, ще ви трябва много познания и умения по програмиране, включително разбиране на концепциите за многопоточност и работа в мрежа.

За да използвате websockets, уеб сървърът на вашия сайт трябва да стартира специална програма, която се очаква да се нарича websocket сървър. Тази програма отговаря за координирането на взаимодействието на всички участници и веднъж стартирана работи без прекъсване.

Много хостинг компании не позволяват дългосрочни програми, освен ако не платите за специален уеб сървър, т.е. сървър, който обслужва само вашия уебсайт. Ако имате обикновен споделен хостинг, най-вероятно няма да можете да хоствате страници, които използват websockets. Дори ако успеете да накарате уебсокет сървър да работи и да го поддържате, вашият собственик на хостинг най-вероятно ще го идентифицира и ще го затвори.

За да ви дадем представа за обхвата на уебсокет сървър, помислете за някои от задачите, които трябва да изпълнява един сокет сървър:

    съставете „речник“ на съобщенията, с други думи, решете кои типове съобщения са приемливи и кои не;

    идентифицирайте грешки при изпращане на съобщения до клиенти и спрете да се опитвате да се свържете с тях, ако изглежда, че вече не съществуват;

    обработва всички данни в RAM, т.е. данни, до които всички клиенти може да имат нужда от достъп и да го правят сигурно и надеждно. Тук има много възможни неявни проблеми, като например когато един клиент се опитва да се присъедини към обмена, докато другият е прекъснат и информацията и за двамата се съхранява в един и същ обект в паметта.

Най-вероятно разработчиците никога няма да създадат сами сървърна програма, която използва уеб сокети, защото... просто не си струва необходимите значителни усилия. Най-лесният подход в тази област би бил да инсталирате чужд websocket сървър и да разработите вашите уеб страници за него. Тъй като използването на частта на JavaScript от стандарта за websocket е лесно, това не би трябвало да създава проблеми.

Друг подход би бил да вземете нечий чужд уебсокет сървърен код и да го приспособите към вашите изисквания. Понастоящем има много проекти (много от които са безплатни и с отворен код), които разработват уеб сокет сървъри за решаване на различни проблеми на различни сървърни езици за програмиране.

Прост уебсокет клиент

От гледна точка на уеб страница, функционалността на websocket е лесна за разбиране и използване. Първата стъпка е да създадете WebSocket обекти му предайте URL адреса. Кодът за това е подобен на следния:

Var socket = нов WebSocket("ws://localhost/socketServer.php");

URL низът започва с текста ws://, който идентифицира връзката с уеб сокет. Този URL адрес сочи към файла на уеб приложението на сървъра (в този случай скриптът socketServer.php).

Стандартът Web Sockets също поддържа URL адреси, които започват с текста wss://, което показва изискването за използване на защитена, криптирана връзка (точно както когато заявявате уеб страница, посочете URL адрес, който започва с https:// вместо http : //).

Websockets могат да се свързват не само с техния уеб сървър. Уеб страница може да отвори връзка към уеб сокет сървър, работещ на друг уеб сървър, без да са необходими допълнителни усилия.

Самият акт на създаване на WebSocket обект принуждава страницата да се опита да се свърже със сървъра. След това трябва да използвате едно от четирите събития на обекта WebSocket: onOpen(когато връзката е установена), onError(когато възникне грешка) onClose(при затваряне на връзката) и onMessage(когато страницата получи съобщение от сървъра):

Socket.onopen = ConnectionOpen; socket.onmessage = messageReceived; socket.onerror = errorOccurred; socket.onopen = връзката е затворена;

Например, ако връзката е успешна, би било хубаво да изпратите съответно съобщение за потвърждение. Това съобщение се доставя с помощта на метода изпрати () WebSocket обект, който се предава обикновен текст като параметър. Следното е функция, която обработва събитието onopen и изпраща съобщение:

Функция connectionOpen() ( socket.send("Потребителско име: [имейл защитен]"); }

Вероятно уеб сървърът ще получи това съобщение и ще отговори на него.

Събитията onError и onClose могат да се използват за изпращане на известия до посетителя на уеб страница. Но най-важното е събитието onMessage, което се задейства, когато се получат нови данни от сървъра. Отново кодът на JavaScript за обработка на това събитие е лесен - ние просто извличаме текста на съобщението от свойството data:

Функция messageReceived(e) ( messageLog.innerHTML += "

Ако уеб страницата реши, че цялата й работа е свършена, тя може да затвори връзката с помощта на метода прекъсване на връзката ():

Socket.disconnect();

От този преглед на websockets можем да видим, че използването на websocket сървър на трета страна е лесно - просто трябва да знаем кои съобщения да изпратим и кои да изчакаме.

Зад кулисите е свършена много работа, за да се направят връзките чрез уеб сокет да работят. На първо място, уеб страницата комуникира чрез нормалния HTTP стандарт. След това тази връзка трябва да бъде надстроена до уебсокет връзка, позволяваща безплатна двупосочна комуникация. В този момент може да има проблеми, ако има прокси сървър между компютъра на клиента и уеб сървъра (както например в типична корпоративна мрежа). Прокси сървърът може да откаже да сътрудничи и ще прекрати връзката. Този проблем може да бъде решен чрез откриване на неуспешна връзка (чрез събитието onError на обекта WebSocket) и прилагане на един от полифилите за сокет, описани на уебсайта GitHub. Тези контейнери използват метод на анкета, за да емулират връзка с уеб гнездо.

Примери за websockets в мрежата

Ако проявявате интерес да изпробвате websockets, има много сайтове онлайн, където можете да започнете разработката си.

За да започнете, опитайте websocket.org, който предоставя прост websocket сървър: уеб страница изпраща съобщение до него и той връща същото съобщение до уеб страницата:

Въпреки че този websocket сървър не е нищо особено, той ви позволява да изпробвате всички функции на обекта WebSocket. Освен това можете да се свържете с този сървър от страница, разположена както на производствения уеб сървър, така и на тестовия уеб сървър на вашия компютър, или дори от страница, просто стартирана от вашия твърд диск:

Var socket = нов WebSocket("ws://echo.websocket.org"); socket.onopen = ConnectionOpen; socket.onmessage = messageReceived; функция connectionOpen() ( socket.send("Потребителско име: [имейл защитен]"); ) функция messageReceived(e) ( var messageLog = document.getElementById("messageLog"); messageLog.innerHTML += "
" + "Отговор на сървъра: " + e.data; )

Има и уебсокет сървъри, които предоставят други възможности, включително следните.

В тази статия ще разгледаме работата с библиотеката phpws, която е необходима за организиране на приложения или WEB приложения, базирани на сокети, и ще изпълним няколко стандартни примера, които са представени на страницата на GitHub хранилище на този проект.

Забележка. Нашите сокети ще работят както от страната на сървъра, така и от страната на клиента. От страна на сървъра това ще се извършва от стандартния WebSocket, който се появи в HTML5, а работата от страната на сървъра, където имаме PHP, ще се извършва от библиотеката phpws. Има много подобни библиотеки, може би най-забележителната Ratchet, която ми се стори тромава за моя малък проект и се спрях на phpws.

Трябва ни Композитор

Много удобно нещо, което ще улесни работата със зависимости и библиотеки, включени в проекти. Според универсалния стандарт за кодиране, или по-просто според правилното писане на код, всички библиотеки, пакети, зависимости или проекти обикновено се съхраняват в хранилища на изходния код, които след това се свързват с проекта чрез няколко команди чрез пакет мениджъри или чрез мениджъри на зависимости. Всеки език има свой собствен мениджър или почти всеки, така че нека се въоръжим с този инструмент и да го инсталираме в системата с команда в Linux

$ curl -s https://getcomposer.org/installer | php

Изтеглихме го, но командите на композитора няма да се изпълняват чрез PATH, така че ще преместим изтегления файл в /usr/local/bin

$ mv composer.phar /usr/local/bin/composer

Изпълняваме командата и получаваме резултата под формата на инструкции и команди на Composer, което показва успешна инсталация

$композитор

За Windows и Mac можете да видите инструкциите извън сайта.

Забележка. Всички зависимости, които трябва да бъдат включени, трябва да бъдат посочени във файла composer.json в основата на проекта, който ще изтегли, актуализира и събере всички зависимости в една папка на доставчика, от която след това може да се зареди чрез автоматичното зареждане на класа. Composer има собствено хранилище на пакети и библиотеки, наречено Packagist, което ви позволява да посочите доставчик/пакет и той ще бъде инсталиран. Да, можете да посочите конкретни адреси на svn/git хранилища в composer.json, но това е неудобно. Много по-удобно е да има някаква централна точка, където има съвпадения на пакети с техните адреси на хранилища. Това е Packagist.

Имаме нужда от библиотеката phpws

За да се свържем с проекта, трябва да отидем в корена на папката на проекта или в подпапка, ако това е част от проекта, и да инсталираме тази библиотека там, но първо трябва да създадем composer.json на това място, което след това ще изпълним през конзолата с помощта на командите на композитора и след като прочетем всичко, ще го инсталираме вместо нас. За да направите това, създайте този файл със следното съдържание

( "хранилища": [ ( "тип": "vcs", "url": "https://github.com/Devristo/phpws" ) ], "изискване": ( "devristo/phpws": "dev-master "))

В този случай посочихме, че изтегляйте директно от хранилището на GitHub без посредничеството на Packagist.

Нека изпълним този файл с командата

$ композитор инсталация

След това в папката ще се появи подпапка на доставчика с изтеглените библиотеки и всичко, което трябва да направим, е да се свържем и да ги използваме.

Имаме нужда от основно разбиране за това как WebSocket работи с PHP

И така, за минута, нека да разберем какво да правим с изтеглените библиотеки и как да ги използваме, няма да навлизам в дълбочина, така че ако е на пръсти, тогава имаме нужда от 2 файла:

  1. client.html е файлът от страна на клиента, който се вижда от лицето зад браузъра. Той използва JavaScript за работа със сокета;
  2. server.php всъщност е нашият сокет сървър, който обработва всички заявки от клиента и му отговаря с обработени отговори.

За да се свържем, трябва да посочим схемата на свързване или комуникационния протокол, ip - адреса на сървъра. Ако е отдалечен сървър, тогава трябва да посочите ip адреса на хоста или VPS, а ако е локален, тогава localhost, който е равен на адреса 127.0.0.0 и също така посочваме порта, на който сървърът обслужва ще бъде стартиран под собствен PID. Всички тези данни се посочват при създаване на екземпляр на връзка.

За клиентската част:

Var socket = "ws://127.0.0.0:12345/";

За сървърната част:

$server = нов WebSocketServer("tcp://127.0.0.0:12345", $loop, $logger);

Стандартен пример за показване на текущото време на сървъра, актуализирано до секунда

За да работи този пример, трябва да изпълните файла server.php веднъж през конзолата и след изпълнение на този скрипт да стартирате сокет сървъра с неговия PID

Какво прави примерът? Примерът показва как до част от секундата сокетът актуализира информацията за времето на сървъра и я издава на клиента

Клиентска част:

Таймери

Време на сървъра

Статус:
Време:


Var socket = нов WebSocket("ws://localhost:12345"); socket.onopen = функция(msg)(document.getElementById("статус").innerHTML = "Онлайн";); socket.onclose = function(msg)( document.getElementById("status").innerHTML = "Offline"; ) socket.onmessage = function(msg)( document.getElementById("time").innerHTML = msg.data; ) ;

Сървърна част:

#!/php -qaddWriter($writer); // Създаване на WebSocket сървър с помощта на SSL $server = new WebSocketServer("tcp://127.0.0.0:12345", $loop, $logger); // Всеки 0,5 секунди изпраща времето до всички свързани клиенти $loop->addPeriodicTimer(0.5, function() use($server, $logger)( $time = new DateTime(); $string = $time->format(" Y-m-d H:i:s"); $logger->notice("Време за излъчване към всички клиенти: $string"); foreach($server->getConnections() as $client) $client->sendString($string); )); // Свързване на сървъра $server->bind(); // Стартиране на цикъла за събития $loop->run();

Стандартен пример за обикновен чат

Показан е пример за обикновен чат. Визуално изглежда като на снимката

Клиентска част:

WebSocket ТЕСТ

WebSocket тест

Сървърът ще повтори вашия отговор!


var socket; функция createSocket(хост) ( ако ("WebSocket" в прозорец) връща нов WebSocket(хост); иначе ако ("MozWebSocket" в прозорец) връща нов MozWebSocket(хост); хвърля нова грешка("Няма поддръжка на уеб сокет в браузъра!" ); ) функция init() ( var host = "ws://127.0.0.0:12345/chat"; try ( socket = createSocket(host); log("WebSocket - status " + socket.readyState); socket.onopen = function(msg) ( log("Добре дошли - състояние " + this.readyState); ); socket.onmessage = function(msg) ( log(msg.data); ); socket.onclose = function(msg) (log( "Disconnected - status " + this.readyState); ); ) catch (ex) ( log(ex); ) document.getElementById("msg").focus(); ) function send() ( var msg = document.getElementById ("msg").value; try (socket.send(msg); ) catch (ex) ( log(ex); ) ) function quit() ( log("Goodbye!"); socket.close(); socket = null; ) функция log(msg) (document.getElementById("log").innerHTML += "
" + msg; ) функция onkey(event) ( if (event.keyCode == 13) ( send(); ) )

Сървърна част:

#!/php -q php chat.php използвайте Devristo\Phpws\Framing\WebSocketFrame; използвайте Devristo\Phpws\Framing\WebSocketOpcode; използвайте Devristo\Phpws\Messaging\WebSocketMessageInterface; използвайте Devristo\Phpws\Protocol\WebSocketTransportInterface; използвайте Devristo\Phpws\Server\IWebSocketServerObserver; използвайте Devristo\Phpws\Server\UriHandler\WebSocketUriHandler; използвайте Devristo\Phpws\Server\WebSocketServer; /** * Този манипулатор на ChatHandler по-долу ще отговаря на всички съобщения, изпратени до /chat (напр. ws://localhost:12345/chat) */ class ChatHandler разширява WebSocketUriHandler ( /** * Уведомява всички, когато даден потребител се присъедини към чата * * @param WebSocketTransportInterface $user */ public function onConnect(WebSocketTransportInterface $user)( foreach($this->getConnections() as $client)( $client->sendString("Потребител ($user->getId()) се присъедини към чат: "); ) ) /** * Излъчване на съобщения, изпратени от потребител до всички в стаята * * @param WebSocketTransportInterface $user * @param WebSocketMessageInterface $msg */ публична функция onMessage(WebSocketTransportInterface $user, WebSocketMessageInterface $msg) ( $this->logger->notice("Излъчване " . strlen($msg->getData()). " bytes"); foreach($this->getConnections() като $client)( $client->sendString(" Потребителят ($user->getId()) каза: ".$msg->getData()); ) ) ) клас ChatHandlerForUnroutedUrls разширява WebSocketUriHandler ( /** * Този клас се занимава с потребители, които не са маршрутизирани */ публична функция onConnect( WebSocketTransportInterface $user)( //не правете нищо $this->logger->notice("Потребителят ($user->getId()) не се присъедини към никоя стая"); ) публична функция onMessage(WebSocketTransportInterface $user, WebSocketMessageInterface $msg) ( //не правете нищо $this->logger->notice("Потребителят ($user->getId()) не е в стая, но се опита да каже: ($ msg->getData())"); ) ) $loop = \React\EventLoop\Factory::create(); // Създаване на регистратор, който записва всичко в STDOUT $logger = new \Zend\Log\Logger(); $writer = нов Zend\Log\Writer\Stream("php://output"); $logger->addWriter($writer); // Създаване на WebSocket сървър $server = new WebSocketServer("tcp://127.0.0.0:12345", $loop, $logger); // Създаване на рутер, който прехвърля всички /chat връзки към класа ChatHandler $router = new \Devristo\Phpws\Server\UriHandler\ClientRouter($server, $logger); // маршрут /чат url $router->addRoute("#^/chat$#i", нов ChatHandler($logger)); // насочване на несравними URL адреси по време на тази демонстрация, за да се избегнат грешки $router->addRoute("#^(.*)$#i", new ChatHandlerForUnroutedUrls($logger)); // Свързване на сървъра $server->bind(); // Стартиране на цикъла за събития $loop->run();

Трябва да стартирате този пример като предишния - веднъж през конзолата, стартирайте файла server.php и през браузъра въведете клиентската част client.html, свързвайки скрипта script.js.

Работа с PHP - сокет сървър от конзолата

За да актуализирате кода на сървъра и да рестартирате, е много удобно да използвате команди за спиране и рестартиране на PHP сървърния файл през конзолата, в противен случай може да възникне неприятна ситуация, когато изглежда, че редактирате кода на сървъра, но той изпълнява стария .

Първо показваме PID на работещия процес на сокет сървър. Научаваме, като разгледаме списъка с работещи сокети през техните портове, използвайки командата:

Netstat --tcp --слушане --програма

Намирайки желания PID от списъка, ние го убиваме с помощта на командата:

Убийте %pid%

В идеалния случай затваряме WebSocket през клиентската част на JavaScript с командата, преди да започнем „убиването“ на PID:

Socket.close(); гнездо = ​​нула;

Satya е посветен на мрежовото програмиране и по-специално на програмирането на сокети в PHP. Има две категории функции за мрежова комуникация в PHP:

  1. Функция fsockopen(низ име на хост, цяло число порт, цяло число грешка_номер, низ грешка_описание, двойно изчакване) - отваря мрежова връзка като файлов поток и връща файлов дескриптор, с който работят функциите fputs, fgets и др.
  2. Функции, които предават информация директно на ниво IP протокол. И това е много по-ниско ниво от нивото, на което работи функцията fsockopen.

Ще бъдат разгледани само функции номер 2, т.к те са по-интересни.
Първо, нека проверим дали сте свързали библиотеката на гнездата.

Можете да проверите това със следния скрипт:

If(extension_loaded("sockets")) echo "разширението е заредено"; else echo "разширението не е заредено"; ?>

Ако разширението не е изтеглено, трябва да го изтеглите.

Така. Най-простият пример в тази статия е echo сървърът. Ехо сървър - това означава, че низът, изпратен от клиента до сървъра, се връща обратно. Тоест сървърът получава някакво съобщение от клиента, прави нещо с него и му го изпраща обратно.

Ще имаме 2 скрипта:

  1. Сървър или демон.
  2. Клиент.

Скрипт "Клиент".

За да реализираме клиента, имаме нужда от следните функции, които работят със сокети:

  1. socket_create(цяло число семейство, цяло число socket_type, цяло число протокол); — функцията създава сокет и връща ресурса на сокета. Първият аргумент е семейството на протокола.Ако връзката е през Интернет, тогава зададената стойност трябва да бъде - AF_INET; Ако връзката ще се осъществи през UNIX сокети - AF_UNIX; Вторият аргумент е типът на сокета. Обикновено SOCK_STREAM се използва за TCP комуникация и SOCK_DGRAM за UPD комуникация. Третият аргумент указва протокола SOL_TCP или SOL_UPD в зависимост от типа.
  2. socket_connect(сокет за ресурси, адрес на низ, порт с цяло число); — след като създадете сокета, трябва да се свържете с него. Първият аргумент е ресурсът на създадения сокет, вторият е IP адресът на сокета, ако семейството на протокола е AF_INET, или името на пътя на сокета на домейна на Unix, ако сокетът е от семейството AF_UNIX. Третият аргумент е номерът на порта, с който трябва да се установи връзката.
  3. socket_read(сокет за ресурси, дължина на цяло число, тип цяло число); — функцията чете броя байтове, посочени в аргумента дължина, от посочения сокет. По подразбиране четенето се извършва без да се вземат под внимание контролните знаци или можете да зададете аргумента тип на PHP_BINARY_READ; за да вземете предвид контролните знаци, трябва да зададете стойността PHP_NORMAL_READ.
  4. socket_write(ресурс сокет, низов буфер, цяла дължина); — функцията записва данни в сокета.
  5. socket_close(гнездо за ресурси); — затваря сокета и освобождава памет.

Списък 1.0 - Клиент

Set_time_limit(0); ob_implicit_flush(); ехо "- Клиент

"; $address = "127.0.0.1"; // localhost адрес. $port = 5555; // порт, с който ще бъде установена връзката. echo "Създаване на сокет..."; $socket = socket_create(AF_INET, SOCK_STREAM , SOL_TCP); if ($socket "; ) else ( echo "OK
"; ) echo "Свързване към сокет..."; $connect = socket_connect($socket, $address, $port); if($connect === false) ( echo "Грешка: ".socket_strerror(socket_last_error() ) "
"; ) else ( echo "ОК

"; $msg = "Здравей сървър!"; echo "Кажете на сървъра \"".$msg."\"..."; socket_write($socket, $msg, strlen($msg)); echo "OK
"; echo "Сървърът каза: "; $awr = socket_read($socket, 1024); echo $awr."
"; $msg = "изход"; echo "Кажете на сървъра \"".$msg."\"..."; socket_write($socket, $msg, strlen($msg)); echo "OK
"; ) if(isset($socket)) ( echo "Затваряне на връзката..."; socket_close($socket); echo "OK
"; } ?>

Сървърен скрипт.

За да реализираме сървъра, се нуждаем от следните функции, които работят със сокети:

  1. Всички функции, описани по-горе.
  2. socket_bind(сокет за ресурси, адрес на низ, порт с цяло число); — функцията свързва адрес към сокет. Аргументът адрес е IP адреса на сокета, ако семейството на протокола е AF_INET, или името на пътя на сокета на домейна на Unix, ако сокетът е от семейството AF_UNIX.
  3. socket_listen(resource socket, integer backlog) - функцията слуша за входящи връзки към сокета. Незадължителният втори аргумент задава максималния размер на опашката от заявки, чакащи връзка.
  4. socket_accept(гнездо за ресурси); - След като гнездото е създадено, обвързано и започнало да слуша, именно тази функция прави сървъра сървър. Функцията приема входящи връзки.

Списък 1.1 - Сървър

Set_time_limit(0); ob_implicit_flush(); ехо "- Сървър

"; $address = "127.0.0.1"; $port = 5555; echo "Създаване на сокет..."; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if($socket "; ) else ( echo "OK
"; ) echo "Свързване на сокет..."; $bind = socket_bind($socket, $address, $port); if($bind "; ) else ( echo "OK
"; ) echo "Слушане на сокет..."; $listen = socket_listen($socket, 5); if($listen "; ) else ( echo "OK
"; ) while(true) ( ​​​​echo "Изчакване... "; $accept = socket_accept($socket); if($accept "; break; ) else ( echo "OK
"; ) $msg = "Здравей, Клиент!"; echo "Изпрати до клиент \"".$msg."\"... "; socket_write($accept, $msg, strlen($msg)); echo " Добре
"; while(true) ( ​​​​$awr = socket_read($accept, 1024); if (false === $awr) ( echo "Грешка: ".socket_strerror(socket_last_error())."
"; break 2; ) else ( if (trim($awr) == "") break; else echo "Клиентът каза: ".$awr."
"; ) if ($awr == "изход") ( socket_close($accept); break 2; ) echo "Кажи на клиента \"".$msg."\"... "; socket_write($accept, $awr , strlen($awr)); echo "ОК
"; ) ) if (isset($socket)) ( echo "Затваряне на връзката..."; socket_close($socket); echo "OK
"; } ?>

Това е всичко. Първо стартирайте сървърния скрипт, той ще създаде, обвърже, ще започне да слуша сокета и ще се настрои в режим на готовност на клиента. След това стартирайте клиента.

Искам също да отбележа, че най-полезната функция е:
socket_select(четене на масив, запис на масив, изключение на масив, цяло число timeout_seconds, цяло число timeout_microseconds); — Функцията контролира промените, настъпващи на възлите. PHP търси нови данни, пристигащи в сокетите, посочени в прочетения масив. PHP търси готовност за получаване на данни на сокетите, посочени в масива за запис. PHP проверява потоците, посочени в аргумента изключение, за грешки. Времето за изчакване указва времето, след което функцията ще върне броя на сокетите, които са променили състоянието си или FALSE.

Тази функция е незаменима за наблюдение на клиенти, висящи на сокета.

Статията показва малка част от всички функции, работещи със сокети, ако се интересувате, изровете ръководствата и прочетете... Успех с експериментите...

В предишната статия говорих за. С теб сме с помощта на сокети създадохме сървър в PHP. И в тази статия ще пишем с вас клиент в PHP, който ще изпрати заявка до сървъра и ще получи отговор от него.

Нося клиентски код в PHP:

header("Content-Type: text/plain;"); //Ще покажем прост текст
set_time_limit(0); //Скриптът трябва да работи постоянно
ob_implicit_flush(); //Всички ехо трябва да бъдат изведени незабавно
$address = "localhost"; //Работният адрес на сървъра
$порт = 1985; // Операционен порт на сървъра (за предпочитане някой рядко използван)
if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP))< 0) {
//AF_INET - семейство протоколи
//SOCK_STREAM - тип сокет
//SOL_TCP - протокол
echo "Грешка при създаване на сокет";
}
иначе(
echo "Сокетът е създаден\n";
}
$резултат = socket_connect($socket, $address, $port);
if ($result === false) (
echo "Грешка при свързване към сокет";
) иначе (
echo "Връзката към сокета беше успешна\n";
}

echo "Съобщение от сървър: $out.\n";
$msg = "15";

socket_write($socket, $msg, strlen($msg)); //Изпращане на съобщение до сървъра
$out = socket_read($socket, 1024); //Прочетете съобщението от сървъра
echo "Съобщение от сървър: $out.\n"; //Изведете съобщение от сървъра
$msg = "изход"; //Команда за изключване
echo "Съобщение до сървъра: $msg\n";
socket_write($socket, $msg, strlen($msg));
echo "Връзката е завършена\n";
//Спрете да работите със сокета
if (isset($socket)) (
socket_close($socket);
echo "Сокетът е затворен успешно";
}
?>

Кодът е добре коментиран, така че мисля, че всичко тук е изключително ясно. Алгоритъмът на клиента е тривиален: създаване на сокет, свързване към сървъра, изпращане на заявки, получаване на отговори, затваряне на връзката. Изпратихме ви номера 15 . Ако сте прочели предишната статия, тогава не забравяйте, че задачата на сървъра е да постави на квадрат това число и да го върне. Следователно, ако стартирате този клиент, ще видите от сървъра 225 (15*15 ). След това даваме командата изключвам, което спира сървъра.

Сега имате минимален набор от знания за работа със сокети и като цяло темата е много интересна, така че можете да я изучите по-подробно. Можете да създадете много сложни приложения клиент-сървър, към които винаги можете да се свържете и да изпратите голямо разнообразие от заявки, които сървърът ще обработи.