- Как создать чат-приложение на Python
- Серверная часть
- Клиентская часть
- Демонстрация функционала
- Заключение
- Saved searches
- Use saved searches to filter your results more quickly
- License
- dmitry-vs/python-messenger
- Name already in use
- Sign In Required
- Launching GitHub Desktop
- Launching GitHub Desktop
- Launching Xcode
- Launching Visual Studio Code
- Latest commit
- Git stats
- Files
- README.md
Как создать чат-приложение на Python
Комната для чата — это интерфейс, который позволяет двум или более людям общаться в чате и отправлять сообщения всем, кто находится в комнате. Сегодня мы поговорим про то, как создать простое чат-приложение на Python и разрешить нескольким клиентам подключаться к нему с помощью сокетов.
Мы используем встроенный в Python сокет-модуль. Он дает возможность осуществлять операции с сокетами. Эти операции широко используются в Интернете: они стоят за любым подключением к любой сети.
Кроме того, для изменения цвета текста, нам понадобится пакет colorama. С помощью этого пакета мы сможем присвоить цвет каждому клиенту в нашем чате. Давайте установим этот модуль:
Поскольку мы используем сокеты, нам нужен серверный и клиентский код. Давайте начнем с серверной части.
Серверная часть
В нашей архитектуре вся работа сервера заключается в выполнении двух основных операций:
- Прослушивание клиентских подключений. Если подключается новый клиент, мы добавляем его в нашу коллекцию клиентских сокетов
- Запуск нового потока для каждого подключенного клиента, прием сообщений, отправленных от клиента, и трансляция их всем другим пользователям.
Приведенный ниже код создает TCP-сокет и привязывает его к адресу сервера, а затем прослушивает поступающие соединения:
import socket from threading import Thread # server's IP address SERVER_HOST = "0.0.0.0" SERVER_PORT = 5002 # port we want to use separator_token # we will use this to separate the client name & message # initialize list/set of all connected client's sockets client_sockets = set() # create a TCP socket s = socket.socket() # make the port as reusable port s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # bind the socket to the address we specified s.bind((SERVER_HOST, SERVER_PORT)) # listen for upcoming connections s.listen(5) print(f"[*] Listening as :")
Обратите внимание, что мы использовали 0.0.0.0 в качестве IP-адреса сервера. Это охватывает все адреса IPv4 на локальном компьютере. Вы можете задаться вопросом, почему мы просто не используем localhost или 127.0.0.1. У сервера может быть два IP адреса, допустим 192.168.1.2 в одной сети и 10.0.0.1 в другой. При указании адреса 0.0.0.0 сервер слушает обе сети.
Мы еще не принимаем соединения, так как не вызывали метод accept() . Приведенный ниже код завершает наш бэкенд:
def listen_for_client(cs): """ This function keep listening for a message from `cs` socket Whenever a message is received, broadcast it to all other connected clients """ while True: try: # keep listening for a message from `cs` socket msg = cs.recv(1024).decode() except Exception as e: # client no longer connected # remove it from the set print(f"[!] Error: ") client_sockets.remove(cs) else: # if we received a message, replace the # token with ": " for nice printing msg = msg.replace(separator_token, ": ") # iterate over all connected sockets for client_socket in client_sockets: # and send the message client_socket.send(msg.encode()) while True: # we keep listening for new connections all the time client_socket, client_address = s.accept() print(f"[+] connected.") # add the new connected client to connected sockets client_sockets.add(client_socket) # start a new thread that listens for each client's messages t = Thread(target=listen_for_client, args=(client_socket,)) # make the thread daemon so it ends whenever the main thread ends t.daemon = True # start the thread t.start()
Как упоминалось ранее, мы добавляем подключенный клиентский сокет в коллекцию наших сокетов. Затем запускаем новый поток и устанавливаем его как поток демона (daemon thread), который выполняет определенную нами функцию listen_for_client() . При наличии клиентского сокета эта функция ожидает отправки сообщения с помощью метода recv() и затем отправляет это сообщение всем другим подключенным клиентам.
Наконец, давайте закроем все сокеты:
# close client sockets for cs in client_sockets: cs.close() # close server socket s.close()
Хорошо, с серверным кодом покончено, теперь давайте углубимся в код клиентской части.
Клиентская часть
Клиент выполняет три основные операции:
- Подключение к серверу
- Прослушивание сообщений, поступающих с сервера и вывод их на консоль (чтобы от сервера поступило сообщение, клиент должен отправить его на сервер, а сервер — распространить)
- Ожидание сообщений от пользователей для их дальнейшей отправки на сервер.
Ниже представлен код для первой операции:
import socket import random from threading import Thread from datetime import datetime from colorama import Fore, init, Back # init colors init() # set the available colors colors = [Fore.BLUE, Fore.CYAN, Fore.GREEN, Fore.LIGHTBLACK_EX, Fore.LIGHTBLUE_EX, Fore.LIGHTCYAN_EX, Fore.LIGHTGREEN_EX, Fore.LIGHTMAGENTA_EX, Fore.LIGHTRED_EX, Fore.LIGHTWHITE_EX, Fore.LIGHTYELLOW_EX, Fore.MAGENTA, Fore.RED, Fore.WHITE, Fore.YELLOW ] # choose a random color for the client client_color = random.choice(colors) # server's IP address # if the server is not on this machine, # put the private (network) IP address (e.g 192.168.1.2) SERVER_HOST = "127.0.0.1" SERVER_PORT = 5002 # server's port separator_token # we will use this to separate the client name & message # initialize TCP socket s = socket.socket() print(f"[*] Connecting to :. ") # connect to the server s.connect((SERVER_HOST, SERVER_PORT)) print("[+] Connected.")
Заодно мы устанавливаем цвет для каждого клиента (увидеть можно будет в выводе). Кроме того, давайте установим имя для каждого клиента, чтобы мы могли различать клиентов между собой:
# prompt the client for a name name = input("Enter your name: ")
Отлично, двигаемся дальше! Приведенный ниже код отвечает за вторую операцию — прослушивание сообщений с сервера и вывод их на консоль:
def listen_for_messages(): while True: message = s.recv(1024).decode() print("\n" + message) # make a thread that listens for messages to this client & print them t = Thread(target=listen_for_messages) # make the thread daemon so it ends whenever the main thread ends t.daemon = True # start the thread t.start()
Кроме того, мы хотим, чтобы прослушивание сообщений происходило в фоне, т.е. чтобы этот поток был потоком-демоном.
Переходим к последней операции — ожиданию сообщений от пользователей с последующей отправкой их на сервер. Сделаем это следующим образом:
while True: # input message we want to send to the server to_send = input() # a way to exit the program if to_send.lower() == 'q': break # add the datetime, name & the color of the sender date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') to_send = f"[] " # finally, send the message s.send(to_send.encode()) # close the socket s.close()
Мы добавляем цвет для каждого клиента, его имя, а также текущую дату и время к отправляемому сообщению. Дальше мы отправляем сообщение с помощью метода send() . Для выхода из программы нужно будет ввести «q» в качестве сообщения.
Демонстрация функционала
Хорошо, теперь, когда мы закончили и серверную, и клиентскую часть, давайте проверим, как всё работает. Во-первых, давайте запустим один экземпляр сервера:
Круто, сервер мониторит предстоящие подключения клиентов, давайте попробуем запустить один экземпляр клиента:
Отлично! Первый клиент подключен к серверу и ему предлагается ввести имя пользователя. Теперь, чтобы убедиться, что он подключен, вернитесь к консоли сервера:
Обратите внимание, что сейчас мы используем адрес localhost (127.0.0.1), так как это одна и та же машина. Но если вы хотите подключиться с других машин в той же сети, вы также можете это сделать, просто измените SERVER_HOST в клиентской части кода с 127.0.0.1 на частный IP-адрес сервера.
Давайте запустим еще один клиент, чтобы они могли поболтать:
Удивительно! Как видите, сообщения клиентов отличаются цветом, что позволяет различать пользователей. Что ж, давайте запустим третьего клиента для развлечения:
Заключение
Отлично, теперь каждое сообщение, отправленное одним клиентом, отправляется всем остальным. Обратите внимание, что цвета меняются при каждом повторном выполнении сценария client.py.
Пожалуйста, сверьтесь с полным кодом, чтобы вы могли легко запустить чат-приложение самостоятельно!
Мы также советуем добавить больше возможностей в эту программу. Например, можно сделать оповещение для всех пользователей при подключении нового клиента!
Итак, сегодня мы поговорили о том, как создать чат-приложение на Python. Надеемся, данная статья была вам полезна!
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
Client-server messenger app
License
dmitry-vs/python-messenger
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Проект представяет собой учебный чат-мессенджер на Python. Состоит из клиентской и серверной частей. Сетевое взаимодействие осуществляется с использованием сокетов. Сервер использует библиотеку select для работы с несколькими клиентами сразу. Для обмена сообщениями используется протокол JIM. Клиент и сервер имеют как консольную, так и графическую версии. Последняя предпочтительнее по удобству и полноте поддерживаемого функционала. Графический интерфейс пользователя реализован с использованием PyQT5. В качестве базы данных используется sqlite, при этом ORM не применяется. Реализован механизм авторизации пользователей с использованием модулей hmac и hashlib.
Рассмотрим графическую версию сервера.
В данном блоке можно задать хост и порт для сервера, а также запустить или остановить его. Если сервер запущен, в поле Status появится значение Started .
Таблица содержит историю активности клиентов: логин, дата и время последнего посещения, IP-адрес, с которого в последний раз заходил пользователь. Данные отсортированы по времени (более новые вверху).
Чтобы клиент мог пользоваться чатом, его нужно сначала зарегистрировать на сервере. Для этого в данном блоке нужно ввести его логин и пароль, затем нажать кнопку Add client .
В данное поле выводится вся информация о работе сервера: служебные данные, сообщения об ошибках, а также все сообщения, которые принимает и отправляет сервер, плюс информация о подключениях и отключениях клиентов.
Рассмотрим графическую версию клиента.
Для начала работы нужно ввести данные для соединения с сервером:
- User name — логин
- Password — пароль
- Server IP — адрес или имя хоста сервера
- Server port — номер порта, на котором работает сервер
Кнопка Connect позволяет выполнить подключение к серверу, кнопка Disconnect — отключение.
Когда клиент успешно подключился к серверу, в данном блоке отображается информация о подключении: логин пользователя, адрес хоста и номер порта сервера.
В блоке Contacts отображается список контактов пользователя. Чтобы добавить новый контакт, нужно ввести логин в поле Add contact и нажать кнопку Add . После этого можно писать данному пользователю сообщения. Если клиенту приходит сообщение от контакта, которого ещё нет в списке, то он автоматически там появляется. Для удаления контакта нужно выбрать его из списка и нажать кнопку Delete selected contact .
Для отправки сообщения контакту нужно выбрать его в списке щелчком левой кнопки мыши. После этого в поле Messages появится история переписки с данным пользователем (если она была ранее). Чтобы послать ему новое сообщение, требуется ввести текст в поле Input и нажать кнопку Send . Для успешной доставки сообщения необходимо, чтобы получатель также был подключен к серверу. В противном случае сервер ответит ошибкой с текстом «client not online». Входящие сообщения будут отображаться в Messages по их получения клиентом.
В данном блоке выводится информация о работе клиента, это служебные данные и сообщения об ошибках.