Сервер на python не хочет подключать больше 1 клиента
Доброе утром всем товарищем программистам. Я написал программу для одногруппников, чтобы вместо денег использовать валюту в Python. Однако, возникла проблема с подключением к серверу, поскольку только один клиент может подключиться, хотя в программе установлено значение "2" для serversocket.listen(2). Знакомый мне посоветовал попробовать библиотеку threading, так что я попробую сейчас использовать этот модуль.
Как работает мой сервер: Когда клиент подключается, сервер генерирует уникальный идентификатор для клиента и сохраняет начальное значение счета в словаре. Затем сервер ожидает сообщения от клиента с указанием суммы и идентификатора получателя. После получения сообщения сервер проверяет, существует ли получатель в словаре клиентов. Если да, то сервер обновляет счета отправителя и получателя, и отправляет клиенту информацию о новых счетах. Если получатель не существует, сервер отправляет сообщение об ошибке.
Код клиента:
Этот код представляет собой клиентскую часть программы, которая подключается к серверу по сокету, взаимодействуя с ним через TCP-соединение. Клиент получает уникальный идентификатор от сервера при подключении, после чего вы можете отправлять запросы серверу, указывая количество очков и идентификатор получателя. В ответ на запрос, сервер обрабатывает данные, меняя количество очков у отправителя и получателя, затем отправляет ответ обновленный баланс отправителя и получателя.
Когда вы вводите quit, клиент отправляет это сообщение серверу и закрывает соединение.
Цель: Сделать так, чтобы к серверу смогли одновременно смогли подключиться хотя бы на данный момент всего два клиента. Также, следует внести изменения в программу для оптимизации её производительности и устойчивости, так чтобы серверы не "падал" и не завершал работу слишком часто. Но приоритетной для меня целью является разобраться с подключением клиентом! Заранее спасибо человеку, который поможет мне!
Код сервера:
import socket
import random
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "localhost"
port = 12345
server_socket.bind((host, port))
server_socket.listen(2)
print("Сервер запущен на порту", port)
clients = {}
def handle_client(client_socket, client_address):
id_value = str(random.randint(100000, 999999))
clients[id_value] = 100
client_socket.send(id_value.encode())
while True:
data = client_socket.recv(1024).decode()
print("Получено от клиента:", data)
if data == "quit":
break
amount, recipient_id = data.split(",")
amount = int(amount)
if recipient_id in clients:
sender_score = clients[id_value]
sender_score -= amount
clients[id_value] = sender_score
recipient_score = clients[recipient_id]
recipient_score += amount
clients[recipient_id] = recipient_score
response = "Ваши очки: {}\nСчет получателя: {}".format(sender_score, recipient_score)
client_socket.send(response.encode())
else:
error_msg = "Неверный идентификатор получателя"
client_socket.send(error_msg.encode())
del clients[id_value]
client_socket.close()
while True:
client_socket, client_address = server_socket.accept()
print("Установлено соединение с клиентом", client_address)
handle_client(client_socket, client_address)
Код клиента:
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Подключение к серверу
host = "localhost"
port = 12345
client_socket.connect((host, port))
client_id = client_socket.recv(1024).decode()
print("Ваш id:", client_id)
while True:
amount = input("Введите количество очков для отправки ('quit' для выхода): ")
if amount == "quit":
client_socket.send(amount.encode())
break
recipient_id = input("Введите id получателя: ")
data = "{},{}".format(amount, recipient_id)
client_socket.send(data.encode())
response = client_socket.recv(1024).decode()
print(response)
client_socket.close()
Ответы (2 шт):
Я смог решить свою проблему, используя библиотеку threading. Я его использую для обработки одновременно нескольких клиентов. Когда клиент подключается к моему серверу, создается новый поток (thread), который обрабатывает взаимодействие с этим клиентом, позволяя серверу обрабатывать другие клиенты параллельно.
Однако, хочу предупредить сразу! Если вы захотите использовать мой способ, то нужно учесть, что хоть и библиотека threading позволяет обрабатывать несколько клиентов одновременно, но а так же увеличивает нагрузку на сервер!
Сейчас я буду пробовать правильно организовывать и управлять потоками. Если вы напишите совет, как это сделать лучше, то буду благодареy.
Как теперь выглядит сервер:
import socket
import random
import threading
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "localhost"
port = 12345
server_socket.bind((host, port))
server_socket.listen(2)
print("Сервер запущен на порту", port)
clients = {}
lock = threading.Lock()
def handle_client(client_socket, client_address):
id_value = str(random.randint(100000, 999999))
with lock:
clients[id_value] = 100
client_socket.send(id_value.encode())
while True:
data = client_socket.recv(1024).decode()
print("Получено от клиента:", data)
if data == "quit":
break
if data == "/balance":
with lock:
response = "Ваши очки: {}".format(clients[id_value])
client_socket.send(response.encode())
elif data.startswith("/trade"):
_, recipient_id, amount = data.split()
amount = int(amount)
with lock:
if recipient_id in clients and amount <= clients[id_value]:
sender_score = clients[id_value]
sender_score -= amount
clients[id_value] = sender_score
recipient_score = clients[recipient_id]
recipient_score += amount
clients[recipient_id] = recipient_score
response = "Очки успешно отправлены"
client_socket.send(response.encode())
else:
response = "Ошибка при отправке очков"
client_socket.send(response.encode())
else:
response = "Неверная команда"
client_socket.send(response.encode())
with lock:
del clients[id_value]
client_socket.close()
def start_server():
while True:
client_socket, client_address = server_socket.accept()
print("Установлено соединение с клиентом", client_address)
client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
client_thread.start()
start_server()
Как теперь выглядит код клиента:
import socket
host = "localhost"
port = 12345
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((host, port))
client_id = client_socket.recv(1024).decode()
print("Подключено к серверу. Ваш идентификатор:", client_id)
while True:
command = input("Введите команду: ")
if command.lower() == 'quit':
client_socket.send('quit'.encode())
break
elif command.lower() == '/balance':
client_socket.send('/balance'.encode())
response = client_socket.recv(1024).decode()
print("Ваши очки:", response)
elif command.startswith('/trade'):
_, recipient_id, amount = command.split()
trade_command = "/trade {} {}".format(recipient_id, amount)
client_socket.send(trade_command.encode())
response = client_socket.recv(1024).decode()
print(response)
else:
print("Неверная команда")
client_socket.close()
Используйте Фреймворк, а не голый сокет. Например минимальный стандартный
https://docs.python.org/3/library/socketserver.html
Тред сервер чтоб обрабатывать блокирующие вещи одновременно, пример из доков:
import socket
import threading
import socketserver
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()