Очень простой чат(клиент/сервер) на Python.

В этой статье мы напишем очень простой консольный чат на популярном языка Python. Состоять он будет из двух частей. Первая чать это сервер, куда будут приходить сообщения клиентов которые подключены к серверу. Втора чать это клиент, которые отправляет сообщения серверу и получает сообщения от сервера.

Постановка задачи.

  • Написать сервер для приема сообщений от клиента и отправки сообщений всем остальным клиентам подключенным к серверу. Будем использовать протокол TCP/IP.
  • Собственно сам клиент. Который коннектится к серверу по TCP/IP. Отправляет и получает сообщения от сервера.
  • Ну и реализуем какое нибудь простое шифрование. Что бы сообщения могли читать только клиенты.

Часть первая. Сервер.

Первым делом на надо создать сокет, который будет принимать соединения скажем на порту 5050 . Для работы с сокет в Python есть модуль который так и называется socket. Подключим его :

import socket 

Создадим сам сокет:

sock = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)


socket.AF_INET — для сокета используем IPv4 . socket.SOCK_DGRAM — тип сокета. Датаграммный сокет — это сокет, предназначенный для передачи данных в виде отдельных сообщений (датаграмм). По сравнению с потоковым сокетом, обмен данными происходит быстрее, но является ненадёжным: сообщения могут теряться в пути, дублироваться и переупорядочиваться. Датаграммный сокет допускает передачу сообщения нескольким получателям (multicasting) и широковещательную передачу (broadcasting).

Теперь свяжем сокет с адресом(интерфейсом) и портом :

sock.bind (('',5050))

Пусты кавычки значат что сокет слушает все доступные интерфейсы.

Теперь нам надо как то принимать сообщения. На совершенно все равно от кого и что получать. Наша задача получить и отправить остальным известным клиентам. По этому мы будем использовать функцию socket.recvfrom(bufsize)  которая нам вернет данные и адрес сокета с которого получены эти данные.

data , addres = sock.recvfrom(1024)  # Буфер в байтах

Для отправки данных будем использовать функцию socket.sendto( bytes, address ) :

 sock.sendto(data,addres) 

Итог у нас такой :

import socket
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind (('94.250.252.115',5050))
client = [] # Массив где храним адреса клиентов
print ('Start Server')
while 1 :
data , addres = sock.recvfrom(1024)
print (addres[0], addres[1])
if addres not in client :
client.append(addres)# Если такова клиента нету , то добавить
for clients in client :
if clients == adress :
continue # Не отправлять данные клиенту который их прислал
sock.sendto(data,clients)

Клиентская часть.

С клиентом немного все посложней. Так как это чат, нам надо получать и отправлять сообщения одновременно. Или не зависимо друг от друга. Для этого нам потребуется многопоточное выполнение нашего кода. Для этого мы будем использовать модуль threading

import threading

Первым делом создадим функцию которая будет получать сообщения от сервера:

def read_sok():
while 1 :
data = sor.recv(1024)
print(data.decode('utf-8'))

Теперь нам надо создать поток и запустить в нем эту функцию:

potok = threading.Thread(target= read_sok)
potok.start()

Теперь весь код с комментариями :

import socket
import threading
def read_sok():
while 1 :
data = sor.recv(1024)
print(data.decode('utf-8'))
server = '192.168.0.1', 5050 # Данные сервера
alias = input() # Вводим наш псевдоним
sor = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sor.bind(('', 0)) # Задаем сокет как клиент
sor.sendto((alias+' Connect to server').encode('utf-8'), server)# Уведомляем сервер о подключении
potok = threading.Thread(target= read_sok)
potok.start()
while 1 :
mensahe = input()
sor.sendto(('['+alias+']'+mensahe).encode('utf-8'), server)

Шифрование .

У нас очень упрощенный вариант, думаю c шифрованием мудрить не будем. Возьмем самый простой симметричный алгоритм XOR. Основная идея алгоритма состоит в том, что если у нас есть некая величина, есть некий шифровальный ключ (другая величина), то можно зашифровать исходные данные через этот ключ, применив операцию XOR побитно. Т.е. если у нас есть исходная фраза a и ключ k, то x = a ^ k. Теперь, если к шифру x опять применить ключ, то получим исходную фразу, т.е. a = x ^ k .

key = 567  # Ключ шифрования

crypt = ''
for i in  message  :
    crypt += chr(ord(i)^key)
 message  = crypt

Я не рассчитываю на уникальность материала, сам учусь ) Строго не судите. Подсказки и доработки приветствуются.