Пишем свой мессенджер P2P
На фоне обсуждения будущего интернет мессенджеров и прочтения статьи «Почему ваш любимый мессенджер должен умереть», решил поделиться своим опытом создания P2P приложения для общения независимо от сторонних серверов. Точнее — это просто заготовка, передающая одно сообщение от клиента серверу, дальнейшее расширение функционала зависит только от Вашей фантазии.
В этой публикации мы напишем 3 простых приложения для связи P2P из любой точки Земного шара — клиент, сервер и сигнальный сервер.
Нам понадобится:
— один сервер с белым статическим IP адресом;
— 2 компьютера за NAT с типом соединения Full Cone NAT (либо 1 компьютер с 2-мя виртуальными машинами);
— STUN-сервер.
Full Cone NAT — это такой тип преобразования сетевых адресов, при котором существует однозначная трансляция между парами «внутренний адрес: внутренний порт» и «публичный адрес: публичный порт».
Вот, что мы можем прочесть о STUN-сервере на Wiki:
«Существуют протоколы, использующие пакеты UDP для передачи голоса, изображения или текста по IP-сетям. К сожалению, если обе общающиеся стороны находятся за NAT’ом, соединение не может быть установлено обычным способом. Именно здесь STUN и оказывается полезным. Он позволяет клиенту, находящемуся за сервером трансляции адресов (или за несколькими такими серверами), определить свой внешний IP-адрес, способ трансляции адреса и порта во внешней сети, связанный с определённым внутренним номером порта.»
При решении задачи использовались следующие питоновские модули: socket, twisted, stun, sqlite3, os, sys.
Для обмена данными, как между Сервером и Клиентом, так и между Сервером, Клиентом и Сигнальным Сервером — используется UDP протокол.
В общих чертах механизм функционирования выглядит так:
Сервер STUN сервер
Клиент STUN сервер
Сервер Сигнальный Сервер
Клиент Сигнальный Сервер
1. Клиент, находясь за NAT с типом соединения Full Cone NAT, отправляет сообщение на STUN сервер, получает ответ в виде своего внешнего IP и открытого PORT;
2. Сервер, находясь за NAT с типом соединения Full Cone NAT, отправляет сообщение на STUN сервер, получает ответ в виде своего внешнего IP и открытого PORT;
При этом, Клиенту и Серверу известен внешний (белый) IP и PORT Сигнального Сервера;
3. Сервер отправляет на Сигнальный Сервер данные о своих внешних IP и PORT, Сигнальный Сервер их сохраняет;
4. Клиент отправляет на Сигнальный Сервер данные о своих внешних IP и PORT и id_destination искомого Сервера, для которого ожидает его внешний IP, PORT.
Сигнальный Сервер их сохраняет, осуществляет поиск по базе, используя id_destination и, в ответ, отдает найденную информацию в виде строки: ‘id_host, name_host, ip_host, port_host’;
5. Клиент принимает найденную информацию, разбивает по разделителю и, используя (ip_host, port_host), отправляет сообщение Серверу.
Приложения написаны на Python версии 2.7, протестированы под Debian 7.7.
Создадим файл server.py с содержимым:
Заполним соответствующие поля разделов: «Внешний IP и PORT СИГНАЛЬНОГО СЕРВЕРА» и «IP и PORT этого КЛИЕНТА».
Создадим файл client.py с содержимым:
Заполним соответствующие поля разделов: «Внешний IP и PORT СИГНАЛЬНОГО СЕРВЕРА» и «IP и PORT этого КЛИЕНТА».
Давайте напишем приложение для чата на Python
Прочитайте это пошаговое руководство, чтобы узнать, как создать полнофункциональное приложение для чата на Python.
Всегда приятно Поболтать!
Сокеты Tkinter + менее чем в 150 строках кода.
Не слишком часто вам случается создавать что-то удивительно простое, но забавное в использовании, чем вы просто не можете дождаться, чтобы поделиться с миром.
Именно это и произошло со мной, поэтому я здесь, чтобы поделиться тем, как я создал простое приложение для чата с довольно сжатым кодом Python. Более того, я реализовал код без каких-либо сторонних зависимостей!
Давайте просто нырнем!
Во-первых, я создал чат-сервер, который мог принимать входящие запросы от клиентов, желающих общаться. Для этого я использовал хорошие старые сокеты и немного многопоточности.
Использование фреймворков, таких как Twisted и Socket Server был вариантом, но это казалось мне излишним для такого простого программного обеспечения, как наше.
Сервер
Вот как мы начинаем наш серверный сценарий (для этого приложения есть только два сценария: один для сервера, а другой для клиента):
Сокеты UDP-это скорее почтовая рассылка (любой может отправить почту получателю, адрес которого он или она знает), поэтому на самом деле им не требуется устанавливать соединение, прежде чем может произойти связь.
После импорта мы настроили некоторые константы для последующего использования:
Теперь мы разбиваем нашу задачу на прием новых соединений, передачу сообщений и обработку конкретных клиентов. Давайте начнем с принятия соединений:
Естественно, после того, как мы отправим новому клиенту приветственное сообщение, он ответит именем, которое он или она хочет использовать для дальнейшего общения. В функции handle_client() первой задачей, которую мы выполняем, является сохранение этого имени, а затем отправка клиенту другого сообщения о дальнейших инструкциях.
После этого наступает основной цикл связи: здесь мы получаем дополнительные сообщения от клиента, и если сообщение не содержит инструкций для выхода, мы просто передаем сообщение другим подключенным клиентам (через минуту мы определим метод широковещания).
Если мы действительно сталкиваемся с сообщением с инструкциями по выходу (т. Е. клиент отправляет
Теперь идет наша функция broadcast() :
Это были все необходимые функции для нашего сервера. Наконец, мы ввели некоторый код для запуска нашего сервера и прослушивания входящих подключений:
Мы join () |/ACCEPT_THREAD так, чтобы основной скрипт ждал его завершения и не переходил к следующей строке, которая закрывает сервер.
Это завершает наш серверный скрипт, который представлен в следующей сути (для тех, кто читает это на смартфонах, посетите эту ссылку для полного кода сервера):
клиент
Это веселее, потому что мы будем писать графический интерфейс! Для наших целей мы используем Tkinter, инструмент построения графического интерфейса Python “батареи включены”. Давайте сначала займемся импортом:
Теперь мы напишем функции для обработки, отправки и получения сообщений. Начнем с получения:
Почему снова бесконечный цикл? Потому что мы будем получать сообщения совершенно недетерминированно и независимо от того, как и когда мы отправляем сообщения. Мы не хотим, чтобы это было приложение для чата по рации, которое может только отправлять или получать одновременно-мы хотим получать сообщения, когда можем, и отправлять их, когда хотим.
Далее мы определяем функцию send() :
После этого мы очищаем поле ввода, а затем отправляем сообщение на сервер, который, как мы видели ранее, передает это сообщение всем клиентам (если это не сообщение о выходе). Если это сообщение о выходе, мы закрываем сокет, а затем приложение GUI (через top.close() )
Мы определяем еще одну функцию, которая будет вызвана, когда мы решим закрыть окно графического интерфейса. Это своего рода функция очистки перед закрытием и закроет соединение с сокетом до закрытия графического интерфейса:
Затем мы создаем фрейм для хранения списка сообщений. Затем мы создаем строковую переменную, в первую очередь для хранения значения, полученного из поля ввода (которое мы скоро определим). Мы устанавливаем эту переменную в «Введите свои сообщения здесь». чтобы предложить пользователю написать свое сообщение. После этого мы создаем полосу прокрутки для прокрутки этого фрейма сообщения. Вот код:
Как только мы получим адрес и создадим сокет для подключения к нему, мы запустим поток для получения сообщений, а затем основной цикл для нашего графического приложения:
Вот и все! Мы закодировали наше приложение для чата. Опять же, полный клиентский сценарий приведен в следующей сути:
Демонстрация
Это отлично подходит для тестирования на нескольких компьютерах. Вы можете, конечно, запустить сервер и клиент на одной машине для тестирования (используя 127.0.0.1 для ХОСТА в вашем клиенте), но видеть, как общение происходит в реальном времени между разными компьютерами, кажется потрясающим. Серверный скрипт будет регистрировать, какие IP-адреса обращаются к нему, а клиентский скрипт сгенерирует графический интерфейс (после запроса адреса хоста), аналогичный следующим скриншотам:
Графический интерфейс клиента
Другой Клиент, подключенный к тому же Серверу
Честно говоря, графический интерфейс выглядит хорошо, учитывая количество строк кода Python за ним, но не очень! Я оставляю это на ваше усмотрение, чтобы это выглядело лучше (и более интуитивно понятным), возможно, сделав интерфейс чата слева направо, как в мессенджере Facebook. Вы даже можете использовать сторонние библиотеки, такие как Kivy для большей красоты и кросс-платформенной переносимости, или вместо этого использовать веб-интерфейс – публикуйте свои идеи в комментариях. Наконец, спасибо, что терпели меня и читали до последнего символа! Я аплодирую вашему терпению”.
Кроме того, я новичок в блогах, поэтому конструктивная критика не только нужна, но и очень нужна! Я открыт для лучших стилей письма, методов и педагогики — не стесняйтесь упоминать их в комментариях.
Простой мессенджер на tkinter,socket и threading
Table of Contents
В этой статье я бы хотел показать как написать простое приложение мессенджер менее чем в 150 строк.
Серверная часть
Использование фреймворков, таких как Twisted и SocketServer, было возможным, но мне показалось это излишним для такого простого программного обеспечения, как наше.
Давайте обозначим константы, отвечающие например за адрес порта и размер буфера.
Теперь мы разбиваем нашу задачу на прием новых соединений, рассылку сообщений и обработку определенных клиентов. Давайте начнем с принятия соединений:
Это просто цикл, который всегда ждет входящих соединений и, как только он его получает, регистрирует соединение (печатает некоторые сведения о соединении) и отправляет подключенному клиенту приветствие. Затем он сохраняет адрес клиента и позже запускает поток обработки для этого клиента. Конечно, мы еще не определили для этого целевую функцию handle_client (), но вот как мы это сделаем:
Теперь пропишем функцию broadcast ():
Эта функция просто отправляет сообщение всем подключенным клиентам и при необходимости добавляет дополнительный префикс. Мы передаем префикс для broadcast () в нашей функции handle_client () и делаем это так, чтобы люди могли точно знать, кто является отправителем конкретного сообщения. Это были все необходимые функции для нашего сервера. Наконец, мы добавили код для запуска нашего сервера и прослушивания входящих соединений:
Мы присоединяемся к ACCEPT_THREAD, чтобы основной скрипт ожидал его завершения и не переходил на следующую строку, которая закрывает сервер. Это завершает наш серверный скрипт.
В итоге получаем вот такой код для серверной части:
Клиентская часть###
Теперь мы напишем функции для обработки отправки и получения сообщений. Начнем с получения:
Почему мы снова используем бесконечный цикл? Потому что мы будем получать сообщения совершенно независимо от того, как и когда мы отправляем сообщения. Мы не хотим, чтобы это было приложение для чата с функциональностью уровня рации. Мы хотим приложение в котором можно отправлять или получать сообщения одновременно; мы хотим получать сообщения, когда сами того пожелаем, и отправлять их, когда захотим.
Функциональность внутри цикла довольно проста; recv () является блокирующей частью. Он останавливает выполнение до тех пор, пока не получит сообщение, а когда это произойдет, мы продвигаемся вперед и добавляем сообщение в msglist. Затем мы определяем msg_list, который является функцией Tkinter для отображения списка сообщений на экране. Далее мы определим функцию send ():
Мы определяем еще одну функцию, которая будет вызываться, когда мы решим закрыть окно с GUI. Это своего рода функция очистки до закрытия, которая закрывает соединение с сокетом до закрытия графического интерфейса:
Это устанавливает в поле ввода значение , а затем вызывает send (). Начнем с определения виджета верхнего уровня и установки его заголовка, как и в любой другой программе на tkinter:
Затем создаём фрейм со списком сообщений, поле для ввода сообщений и скроллбар для перемещения по истории переписки
“Упаковываем” наши элементы и размечаем их расположение в окне:
После этого мы создаем поле ввода для пользователя, чтобы ввести свое сообщение, и привязать его к строковой переменной, определенной выше. Мы также привязываем его к функции send (), чтобы всякий раз, когда пользователь нажимает return, сообщение отправлялось на сервер.
Далее мы создаем кнопку отправки, если пользователь желает отправить свои сообщения, нажав на нее. Опять же, мы связываем нажатие этой кнопки с функцией send ().
И да, мы также упаковываем все то, что создали только сейчас. Кроме того, не забудьте использовать функцию очистки on_closing (), которая должна вызываться, когда пользователь хочет закрыть окно GUI:
И вот мы подходим к завершению. Мы еще не написали код для подключения к серверу. Для этого мы должны запросить у пользователя адрес сервера. Я сделал это, просто используя input (), чтобы пользователь встретился с подсказкой командной строки, запрашивающей адрес хоста перед запуском окна с графическим интерфейсом. В будущем можно добавить виджет для этой цели. А пока вот так:
Как только мы получаем адрес и создаем сокет для подключения к нему, мы запускаем поток для получения сообщений, а затем основной цикл для нашего приложения с графическим интерфейсом:
Вот и всё! Теперь наш скрипт клиентской части выглядит вот так:
Да, наше приложение не может тягаться с такими гигантами как: telegram, viber, клиентами xmpp/jabber; однако нам удалось создать простой чат, который каждый может развить в что-то своё: сделать уклон в безопасность(например шифруя передаваемые пакеты) или в хороший ux/ui. Получилась своего рода база для чего-то большего и это круто. Спасибо за прочтение, буду рад любым замечаниям и пожеланиям. Традиционно исходный код программы доступен в моём репозитории на github.
«Хочу как Дуров»: пишем простой мессенджер
В последнее время растёт популярность приложений для обмена сообщениями. Пользователи предпочитают мессенджеры, потому что они позволяют взаимодействовать в режиме реального времени. В этой статье мы разберём процесс создания простого приложения для обмена мгновенными сообщениями. Не будем сильно углубляться в нюансы разработки: мы напишем рабочий мессенджер, который в дальнейшем можно будет улучшить.
Статья подойдёт состоявшимся программистам и тем, кто только интересуется, как войти в IT.
Используемые технологии и инструменты
Подготовка
Структура будущего приложения выглядит примерно так:
Установите Node.js и MongoDB. Кроме того, нам понадобится библиотека AngularJS, скачайте её и скопируйте в папку lib каталога Client.
Примечание: созданный мессенджер можно будет интегрировать в качестве виджета в любой проект.
Серверная часть
Шаг 1. Запуск проекта
Перейдите в каталог Server и выполните команду:
Она запустит новый проект.
Укажите все необходимые сведения. В результате будет создан файл package.json примерно следующего вида:
Шаг 2. Установка зависимостей
Выполнение этих команд установит необходимые зависимости и добавит их в package.json :
Выглядеть они будут примерно так:
Шаг 3. Создание сервера
Создадим сервер, который обслуживает порт 3000 и возвращает HTML-файл при вызове. Для инициализации нового соединения сокету нужно передать HTTP-объект. Событие connection будет прослушивать входящие сокеты, каждый сокет будет выпускать событие disconnect, которое будет вызвано при отключении клиента. Мы будем использовать следующие функции:
Создайте сервер с именем server.js . Он должен:
В результате ваш сервер будет выглядеть примерно так:
Клиентская часть
Создайте файлы index.html в каталоге Client, style.css в каталоге CSS и app.js в каталоге js.
Client/index.html
Пусть это будет простой HTML-код, который получает и отображает наши сообщения.
Включите скрипты socket.io-client и angular.js в ваш HTML:
socket.io служит для нас клиентом. Он по умолчанию подключается к хосту, обслуживающему страницу.
В результате index.html должен выглядеть примерно так:
CSS/style.css
Чтобы придать нашей странице внешний вид окна чата, добавим немного стилей. Вы можете использовать любую CSS-библиотеку. Получим следующее:
js/app.js:
Создайте Angular-приложение и инициализируйте соединение сокета. Для этого нужны следующие функции:
Теперь, когда будет набран текст сообщения и нажата кнопка, вызовите функцию отправки сообщения. Когда сокет получит сообщение, отобразите его.
В результате app.js будет выглядеть примерно так:
Запуск приложения
Перейдите в папку с server.js и запустите команду:
Сервер начнет работу на порте 3000. Чтобы в этом убедиться, перейдите по ссылке в браузере:
Ваш собственный мессенджер готов!
Что можно улучшить?
Можно создать базу данных для хранения информации о пользователях и истории сообщений. Лучше, если она будет масштабируемой, потому что в дальнейшем это позволит добавить больше функций.
Установите Mongoose или MongoDB для работы с базами данных Mongo:
Можете ознакомиться с документацией по их использованию: mongoose и mongodb.
Схема должна получиться примерно следующего вида:
Собеседникам могут быть присвоены следующие статусы:
Предположим, что собеседник отклонил запрос на приватную беседу. В таком случае отправитель должен иметь возможность снова направить запрос.
Неплохо было бы реализовать для пользователя функционал сохранения сообщений в дополнительные коллекции. Пусть каждый её объект содержит сообщение, отправителя, получателя и время. Спроектируйте вашу базу данных в соответствии с конкретными потребностями и методами обработки сообщений.
Также вы можете создать REST API для обслуживания клиента. Например, конечную точку, отправляющую домашнюю страницу, из которой пользователи могут выполнять другие запросы.
Некоторые из возможных конечных точек API:
Вот какой мессенджер получился у автора статьи:
Внешний вид приложения
Исходный код приложения можно найти на GitHub.
Пишем чат на Python и Django
Добрый день, друзья. В преддверии старта курса «Web-разработчик на Python» традиционно делимся с вами полезным переводом.
Вы видите перед собой руководство, которое расскажет, как создать приложение-чат на Python, Django и React.
В отличие от других руководств, я не использую Python и Django для WebSocket-соединений. Несмотря на то, что это звучит круто с технической точки зрения, работает это довольно вяло и само по себе затратно, особенно, если у вас приличное количество пользователей. Такие языки, как C++, Go и Elixir намного лучше справляются с ядром чата.
В этом руководстве мы будем использовать Stream, API для чата, которое позаботится о WebSocket- соединениях и других тяжелых аспектах, используя Go, Raft и RocksDB.
Шаг 1: Интерфейс демо-чата на React
Прежде чем мы начнем думать о Python-части, давайте развернем простенький интерфейс на React, чтобы у нас было что-то красивое и визуальное:
Замените код в src/App.js на следующий:
Шаг 2: Установка Django/Python (пропустите этот шаг, если у вас уже есть все необходимое)
Убедитесь, что у вас есть Python 3.7 и он запущен:
Если не сработало, попробуйте следующий код:
Теперь, когда вы в своей виртуальной среде, вы должны увидеть python 3 при запуске:
Чтобы создать новый проект на Django, используйте следующий код:
И запустите приложение:
Шаг 3: Авторизация пользователей
Следующий шаг – настройка авторизации пользователей в Django.
Перейдите на http://localhost:8000/admin/ и войдите. Вуаля!
Вы увидите вкладку администратора на подобие той, что ниже:
Шаг 4: Django Rest Framework
Один из моих любимых пакетов для интеграции React с Django – это Django Rest Framework. Чтобы все заработало, нужно создать конечные точки для:
Чтобы установить Djoser, используйте следующее:
После этого отредактируйте urls.py и измените содержимое файла следующим образом:
По завершении, отредактируйте settings.py и внесите изменения:
Для получения дополнительной информации о конечных точках API, которые предоставляет Djoser, посмотрите следующее:
Теперь давайте продолжим и протестируем конечную точку регистрации:
Шаг 5: Генерация токенов для доступа к Stream-серверу чата
Теперь нам нужно настроить представления Djoser для генерации токенов Stream. Итак, начнем.
Давайте немного упорядочим наши файлы и создадим папку приложения чата в нашем проекте (убедитесь, что вы находитесь в правильном каталоге):
Создайте кастомный сериализатор в auth/serializers.py с помощью следующей логики:
И последнее, используйте кастомный сериализатор, чтобы обновить файл settings.py :
Чтобы убедиться, что он работает, попадите в конечную точку с помощью POST-запроса:
Шаг 6: Интеграция авторизации в React
По очевидным причинам, добавление авторизации к фронтенду – это важный шаг. В нашем случае это особенно полезно, поскольку мы можем извлечь токен пользователя из API (которое работает на Python) и динамически использовать его при отправке сообщений.
Во-первых, установите CORS – пакет промежуточного программного обеспечения для Django:
И наконец добавьте следующее к вашему файлу settings.py :
Следующий шаг потребует внесения нескольких изменений в ваш интерфейс. Для начала вам нужно будет убедиться, что у вас есть все зависимости, установленные через yarn:
Далее создайте следующие файлы в директории src/ :
App.js
AuthedRoute.js
UnauthedRoute.js
withSession.js
Login.js
Chat.js
Обязательно замените YOUR_STREAM_APP_ID на валидный ID приложения Stream, который можно найти на дашборде.
Перезапустите приложение на фронтенде и вы увидите авторизацию! Введите адрес электронной почты и пароль, токен будет запрошен и сохранен в локальном хранилище.
Шаг 7: Отправка сообщений с сервера Python
Если вы внезапно захотите создать API чата с использованием вашего бэкенда на Python, есть специальная команда, которую можно использовать.
Убедитесь, что установленные приложения выглядят следующим образом в settings.py :
Далее создайте каталог chat/management/commands. В этот каталог добавьте файл с именем broadcast.py со следующим содержанием:
Вы можете попробовать отправить сообщение в чат следующим образом:
И вы увидите такой отклик:
Последние мысли
Надеюсь, вам понравилось это руководство по созданию приложения-чата на Django, Python и React!
Для интерактивного тура по Stream Chat, пожалуйста, взгляните на наше руководство по созданию API на сайте Stream. Если вам нравится копаться в коде компонентов Stream Chat React, полную документацию вы можете найти здесь. Если вам захочется создать чат на Stream, мы рады предложить различные SDK для популярных языков и фреймворков до последней iOS (Swift).