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.
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.