Какво е WebSocket и как да се внедри в Python?
WebSocket е мрежова технология, предоставена от HTML5 за пълнодуплексна комуникация между браузъри и сървъри. Това е усъвършенствана технология, която прави възможно отварянето на двупосочна интерактивна комуникация.
С WebSocket API можете да изпращате съобщения до отдалечен сървър и да получавате управлявани от събития отговори, без да се налага да търсите сървъра за отговор. В сравнение с HTTP, непостоянен протокол, WebSocket е протокол за постоянна мрежова комуникация.
Както показва диаграмата по-горе, тя не само позволява на клиента да поиска сървъра, но също така позволява на сървъра активно да изпраща данни на клиента. Това е истински двупосочен равен диалог, който принадлежи към един вид сървърна технология за натискане.
Функции на WebSocket
- Въз основа на TCP протокола, внедряването от страна на сървъра е относително лесно.
- Добра съвместимост с HTTP протокол. Портовете по подразбиране също са 80 и 443, а HTTP протоколът се използва във фазата на ръкостискане, така че не е лесно да се екранира по време на ръкостискането и може да преминава през различни HTTP прокси сървъри.
- Форматът на данните е сравнително лек, разходите за производителност са малки и комуникацията е ефективна.
- Могат да се изпращат както текстови, така и двоични данни.
- Няма ограничение за същия произход и клиентите могат да комуникират с всеки сървър.
- Идентификаторът на протокола е
ws
(илиwss
, ако е шифрован), а URL адресът на сървъра е URL адресът, например:ws(s)://test.com:80/some/path
Защо WebSocket
Без гражданство
В контекста на архитектурата на уеб приложение, HTTP е протокол за заявка-отговор, използван в модела клиент/сървър, при който клиентът изпраща HTTP заявка до сървър и сървърът отговаря с искания ресурс.
HTTP протоколът обаче е без състояние, т.е. третира всяка заявка като уникална и независима единица. Протоколите без състояние имат някои предимства, например сървърът не трябва да пази информация за сесията и следователно не трябва да съхранява данни.
Това също означава, че излишната информация за заявката се изпраща във всяка HTTP заявка и отговор, като например използването на бисквитки за проверка на потребителския статус.
Тъй като взаимодействието между клиенти и сървъри се увеличава, количеството информация, изисквано от HTTP протокола за комуникация между клиенти и сървъри, нараства бързо.
Полудуплекс
Друг недостатък е, че HTTP също е полудуплексен протокол, тоест потокът от информация в същото време може да бъде само еднопосочен: клиентът изпраща заявка до сървъра и сървърът отговаря на заявката. Този полудуплексен протокол прави ефективността на комуникацията ниска.
Инициализация на клиента
В същото време HTTP протоколът има недостатък: комуникацията може да бъде инициирана само от клиента. Следователно, ако сървърът има промяна на състоянието, той не може да уведоми клиента.
Заобиколни решения
За да се подобри ефективността на комуникацията на HTTP протокола, се прилагат следните методи:
- Проучване: От време на време се прави заявка, за да се разбере дали сървърът има нова информация.
- Дълго запитване: Клиентът изисква информация от сървъра и поддържа връзката за определен период от време.
- Технология за поточно предаване: Клиентът изпраща заявка, а сървърът изпраща и поддържа отворен отговор, който непрекъснато се актуализира и поддържа отворен.
Въпреки това нито един от горните методи не осигурява комуникация почти в реално време и те също така въведоха много допълнителни и ненужни заглавни данни и забавяния.
Ето защо „Майкъл Картър“ от група хора предложи WebSocket, което е естествена пълнодуплексна, двупосочна, едносокетна връзка, която решава проблема с HTTP протокола, който не е подходящ за комуникация в реално време.
Ръкостискане на WebSocket
Типично HTTP ръкостискане изглежда така:
GET / HTTP/2 Host: google.com user-agent: curl/7.79.1 accept: */* HTTP/2 301 location: https://www.google.com/ content-type: text/html; charset=UTF-8 date: Mon, 03 Oct 2022 17:50:02 GMT expires: Wed, 02 Nov 2022 17:50:02 GMT cache-control: public, max-age=2592000 server: gws content-length: 220 x-xss-protection: 0 x-frame-options: SAMEORIGIN
Въпреки че самият WebSocket също е нов протокол на приложния слой, той не може да съществува независимо от HTTP. По-конкретно, ние изграждаме екземпляр на WebSocket на клиента и го свързваме с адрес на сървър, към който трябва да бъде свързан. Когато клиентът се свърже със сървъра, той ще изпрати на сървъра http съобщение, подобно на следното:
Host: 127.0.0.1:8081 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: 1wX9ZDz+x2c+7PoKBhr+eA== Sec-WebSocket-Version: 13 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits User-Agent: Python/3.10 websockets/10.3
Можете да видите, това е HTTP съобщение за заявка за получаване. Обърнете внимание, че в съобщението има заглавка за надстройка. Неговата функция е да каже на сървъра, че комуникационният протокол трябва да бъде превключен на WebSocket. Ако сървърът поддържа протокола WebSocket, протоколът се превключва към WebSocket и към клиента едновременно се изпраща заглавка на отговор, подобна на следната:
Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: yBKlMEVMvp6dGL6qj4OH/T6zd5o= Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=12; client_max_window_bits=12 Date: Mon, 03 Oct 2022 18:29:32 GMT Server: Python/3.10 websockets/10.3
Можете да видите, че върнатият код за състояние е 101, което показва, че протоколът е преобразуван в WebSocket. Горният процес се извършва чрез HTTP комуникация, която се нарича WebSocket протокол Handshake. След тази точка клиентът и сървърът установяват WebSocket връзка и последващата комуникация се базира на WebSocket.
Внедряване на WebSocket Python
След като вече разбирате как работи WebSocket, нека се опитаме да внедрим WebSocket сървър с помощта на Python.
Инсталирайте websockets lib
Първо трябва да инсталираме websockets
Python библиотека:
$ pip install websockets Collecting websockets Downloading websockets-10.3-cp310-cp310-manylinuxwss
5_x86_64.manylinux1_x86_64.manylinuxwss
12_x86_64.manylinux2010_x86_64.whl (111 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 111.5/111.5 kB 1.9 MB/s eta 0:00:00 Installing collected packages: websockets Successfully installed websockets-10.3web_server.py
сървър
import asyncio import websockets async def handler(ws, path): data = await ws.recv() reply = f"Data received: {data}" await ws.send(reply) if __name__ == "__main__": start_server = websockets.serve(handler, "127.0.0.1", 8081) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever()
Клиент
import asyncio import websockets async def connect(): async with websockets.connect("ws://127.0.0.1:8081/") as websocket: await websocket.send("hello world") print(f"Reuqest headers:\n{websocket.request_headers}") response = await websocket.recv() print(f"Response headers:\n{websocket.response_headers}") print(response) if __name__ == "__main__": asyncio.get_event_loop().run_until_complete(connect())
За да стартирате като сървър:
$ python web_server.py
като клиент:
$ python web_client.py Reuqest headers: Host: 127.0.0.1:8081 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: 1wX9ZDz+x2c+7PoKBhr+eA== Sec-WebSocket-Version: 13 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits User-Agent: Python/3.10 websockets/10.3 Response headers: Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: yBKlMEVMvp6dGL6qj4OH/T6zd5o= Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=12; client_max_window_bits=12 Date: Mon, 03 Oct 2022 18:29:32 GMT Server: Python/3.10 websockets/10.3 Data received: hello world