Console chat in Python. Implementation of registration in the chat

I ask for your advice. I want to implement a simple chat in python with one condition-registration of "chat participants". (The nickname of the chat participant can be reserved for yourself, and by entering a password-go to the chat under your nickname)

I implemented the logic of a regular client-server chat and there were no problems until the process of "registering" in the chat appeared.

Working logic:

- Соединение с сервером
- Введение имени
- Утверждение, что имя введено верно
- Введение пароля
- Повторное введение пароля
- Пользователь заходит в общий чат 

I will describe the problem in words: I can't implement it a method/principle/logic in which, when registering a user, the server would listen only to sockets from this user. Simply put, any sockets from other users throw off all the logic. It turns out this way: user # 1 is registered (any stage), user #2 comes in and knocks the registration to user #1. I can't figure out how to create a "session" with a specific user. Please help me. The code is given below:

Client code:

import socket
import threading

SERVER_ADDRESS = ('localhost', 8125)
sor = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sor.bind(('', 0))
sor.sendto(('Connect to server').encode('utf-8'), SERVER_ADDRESS)


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


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


while True:
    message = input()
    sor.sendto((message).encode('utf-8'), SERVER_ADDRESS)

Code servers:

import socket

SERVER_ADDRESS = ('localhost', 8125)

server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(SERVER_ADDRESS)
clients = []
members = {}
print("Server is running")

#ТУТ БОЛЬШАЯ ФУНКЦИЯ "РЕГИСТРАЦИИ"
#С ВВОДОМ ИМЕНИ, ПОДТВЕРЖДЕНИЕМ, ПАРОЛЕМ
def register_on_chat(port_address):
    register_data = 'Необходимо пройти регистрацию, введите свой ник: '
    server_socket.sendto(register_data.encode('utf-8'), address)

    def confirm_nickname(port_address):
        name, address = server_socket.recvfrom(1024)
        registration_data = f"Ваш ник {name.decode('utf-8')}? Введите Уes или No."
        server_socket.sendto(registration_data.encode('utf-8'), address)
        append_to_list(name, port_address)

    def new_nickmane(address):
        registration_data = 'Введите свой ник: '
        server_socket.sendto(registration_data.encode('utf-8'), address)
        confirm_nickname(address)

    def append_to_list(name, port_address):
        data, address = server_socket.recvfrom(1024)
        if data.decode('utf-8') == 'Yes':
            get_pass(name)
        elif data.decode('utf-8') == 'No':
            new_nickmane(port_address)

    def get_pass(name):
        pass_data_1 = f"Привет {name.decode('utf-8')} Введите пароль для своего ника: "
        server_socket.sendto(pass_data_1.encode('utf-8'), address)
        password_1, adr= server_socket.recvfrom(1024)
        pass_data_2 = "Повтори пароль"
        server_socket.sendto(pass_data_2.encode('utf-8'), address)
        password_2, adr = server_socket.recvfrom(1024)

        if password_1 == password_2:
            members[name.decode('utf-8')] = password_1.decode('utf-8')
            pass_data_3 = "Отлично, регистрация прошла успешно"
            server_socket.sendto(pass_data_3.encode('utf-8'), address)
            print(members)
        else:
            pass_data_4 = "Давай-ка попробуем снова"
            server_socket.sendto(pass_data_4.encode('utf-8'), address)
            get_pass(name)

    confirm_nickname(port_address)


while True:
    data, address = server_socket.recvfrom(1024)
    print(address[0], address[1])
    if address not in clients:
        clients.append(address)
        register_on_chat(address)
        text = "Регистрация прошла успешно. Добро пожаловать в чат!"
        server_socket.sendto(text.encode('utf-8'), address)

    for client in clients:

        if client == address:
            text_from_client = data.decode('utf-8')
            print(text_from_client)

            continue

        server_socket.sendto(data, client)

Thank you for your advice.

Author: fer0m, 2019-12-06

1 answers

You need to create sessions for users and separate them from receiving data.

class Session:
    def __init__(self, address, sock):
        self.state = 'init'
        self.address = address

    def on_message(self, message):
        if self.state == 'init':
             answer = 'Необходимо пройти регистрацию, введите свой ник: '
        elif self.state == 'waitname':
             answer = f'Ваш ник {message}'         
             self.nick = message
        .......
        return answer



....

clients = {}

while True:
    data, address = server_socket.recvfrom(1024)
    session = clients.get(address, None)
    if not session:
        session = Session(address,server_socket)
        clients[address] = session
    answer = session.on_message(data.decode('utf-8'))
    self.sock.sendto(answer.encode('utf-8'), address)
    if session.state == 'chat':
        for other_session in clients.values():
            if other_session.state == 'chat':
                self.sock.sendto(f"{session.nick}: {data}\n".encode('utf-8'), other_session.address)

The Session class will store the chat state and ask the next question depending on that state. And the clients dictionary will be a session binding to a specific client, not just a list of addresses.

It is possible without a class, and the state is stored in the dictionary.

 3
Author: eri, 2019-12-06 23:39:44