Skip to content

Task 4

Реализовать двухпользовательский или многопользовательский чат. Реализация многопользовательского часа позволяет получить максимальное количество баллов. Реализовать с помощью протокола TCP – 100% баллов, с помощью UDP – 80%.

Обязательно использовать библиотеку threading. Для реализации с помощью UDP, thearding использовать для получения сообщений у клиента.

Для применения с TCP необходимо запускать клиентские подключения И прием и отправку сообщений всем юзерам на сервере в потоках. Не забудьте сохранять юзеров, чтобы потом отправлять им сообщения.

server_chat.py

import threading

from server import Server

class ChatServer(Server):
    def __init__(self, host='localhost', port=12345):
        super().__init__(protocol_type="TCP", host=host, port=port)
        self.clients = {}  # {имя_пользователя: соединение}

    def broadcast(self, message, sender_name):
        for name, conn in self.clients.items():
            if name != sender_name:
                try:
                    conn.sendall(message.encode())
                except Exception as e:
                    print(f"Failed to send message to {name}: {e}")
                    self.clients.pop(name) 

    def private_message(self, message, recipient_name):
        if recipient_name in self.clients:
            try:
                self.clients[recipient_name].sendall(message.encode())
            except Exception as e:
                print(f"Failed to send private message to {recipient_name}: {e}")
                self.clients.pop(recipient_name)

    def handle_client(self, conn, addr):  #  в отдельном потоке
        print(f"New connection: {addr}")
        try:
            conn.send("Enter your name: ".encode())
            name = conn.recv(1024).decode()
            self.clients[name] = conn 

            conn.send(f"Welcome to the chat, {name}!".encode())
            print(f"{name} has joined the chat")

            while True:
                message = conn.recv(1024).decode()
                if not message:
                    break
                print(f"Received from {name}: {message}")

                if message.startswith('/pm'):   # '/pm' - лс
                    parts = message.split(' ', 2)
                    if len(parts) == 3:
                        recipient_name = parts[1]
                        private_message = f"Private from {name}: {parts[2]}"
                        self.private_message(private_message, recipient_name)
                    else:
                        conn.send("Usage: /pm recipient_name message".encode())
                else:
                    broadcast_message = f"{name}: {message}"
                    self.broadcast(broadcast_message, name)

        except Exception as e:
            print(f"Error handling client {addr}: {e}")
        finally:
            print(f"Client {name} disconnected")
            self.clients.pop(name, None)
            conn.close()

    def start(self):
        print(f"Server started at {self.host}:{self.port}")
        while True:
            conn, addr = self.socket.accept()
            thread = threading.Thread(target=self.handle_client, args=(conn, addr))
            thread.start()

if __name__ == "__main__":
    server = ChatServer()
    server.start()

client_chat.py

import threading

from client import Client

class ChatClient(Client):
    def __init__(self, server_host='localhost', server_port=12345):
        super().__init__(protocol_type="TCP", server_host=server_host, server_port=server_port)

    def send_messages(self):
        while True:
            message = input()
            if message:
                self.send_message(message)

    def receive_messages(self):
        while True:
            try:
                message = self.receive_response()
                if message:
                    print(message)
            except:
                print("Connection to server lost.")
                break

    def start(self):
        send_thread = threading.Thread(target=self.send_messages)
        send_thread.start()

        receive_thread = threading.Thread(target=self.receive_messages)
        receive_thread.start()

if __name__ == "__main__":
    client = ChatClient()
    client.start()