Изменить переменную сервера из клиентского потока (threading, python)
Я реализовал простую сетевую "игру" на Python - сервер рисует случайное число, а затем клиент пытается угадать его. Мое приложение отлично работает, когда клиент угадывает номер, он отключается от сервера (он обрабатывается на стороне клиента).
Однако, после правильной догадки, число остается неизменным. Я хотел бы изменить приложение, так что, когда клиент угадывает номер, сервер должен затем rand новый номер, поэтому другие клиенты должны угадать новый. Как я могу это сделать?
Некоторые шаблоны, просто чтобы обратить внимание на проблему:
#!/usr/bin/env python
from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys
class Handler(threading.Thread):
def __init__(self, connection, randomnumber):
threading.Thread.__init__(self)
self.connection = connection
self.randomnumber = randomnumber
def run(self):
while True:
try:
data = self.connection.recv(1024)
if data:
print data
try:
num = int(data)
if Server.guess(num) :
msg = "You won! This is the right number!"
self.connection.send(msg)
break
else :
msg = "Try again!"
self.connection.send(msg)
except ValueError, e:
msg = "%s" % e
self.connection.send(msg)
else:
msg = "error"
self.connection.send(msg)
except socket.error:
self.connection.close()
break
self.connection.close()
class Server:
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server_socket = None
self.randnum = randint(1, 100)
@classmethod
def guess(cls, no):
if cls.randnum == no:
cls.randnum = randint(1, 1000)
result = True
else:
result = False
return reslut
def run(self):
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.ip, self.port))
self.server_socket.listen(10)
print 'Num is %s' % self.randnum
while True:
connection, (ip, port) = self.server_socket.accept()
c = Handler(connection, self.randnum)
c.start()
except socket.error, e:
if self.server_socket:
self.server_socket.close()
sys.exit(1)
if __name__ == '__main__':
s = Server('127.0.0.1', 1234)
s.run()
Ответы
Ответ 1
Создайте случайное число, которое будет совместно использоваться как сервером, так и всем клиентом, должен быть только экземпляр этого, следовательно, это должен быть атрибут класса.
Добавьте функцию класса guess
, которые возвращают False
при некорректном угадывании и при правильном изменении предположения randnum
и возвращают True
class Server:
randnum = randint(1, 1000) # class attribute created
@classmethod
def guess(cls, no): # To be used "guess" if `no` attribute if the same as `cls.randnum`
if cls.randnum == no:
cls.randnum = randint(1, 1000)
result = True
else:
result = False
return result
def __init__(self, ip, port):
# ...
Клиент должен называть эту функцию Server.guess
каждый раз.
Ответ 2
На самом деле ваша проблема возникает из-за того, что вы создаете randnum
как метод экземпляра (см. ваш self.randnum
), как объяснил @shanmuga, если вы просто объявляете его атрибутом класса и удаляете метод экземпляра, который он решает вашу проблему (т.е. объявить ее непосредственно в классе).
Как побочная проблема (не являющаяся экспертом в сокете), когда вы отправляете сообщение клиенту, вы можете закодировать их как объект байта (в методе run
обработчика, я изменил self.connection.send(msg)
на self.connection.send(msg.encode())
). Также обратите внимание, что я использовал Python 3.6 (которые в основном меняют стиль операторов печати)
Смотрите код ниже:
#!/usr/bin/env python
from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys
class Handler(threading.Thread):
def __init__(self, connection, randomnumber):
threading.Thread.__init__(self)
self.connection = connection
self.randomnumber = randomnumber
def run(self):
while True:
try:
data = self.connection.recv(1024)
if data:
print(data)
try:
num = int(data)
if Server.guess(num) :
msg = "You won! This is the right number!"
self.connection.send(msg.encode())
break
else :
msg = "Try again!"
self.connection.send(msg.encode())
except ValueError as e:
msg = "%s" % e
self.connection.send(msg.encode())
else:
msg = "error"
self.connection.send(msg.encode())
except socket.error:
self.connection.close()
break
self.connection.close()
class Server:
randnum = randint(1,100)
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server_socket = None
@classmethod
def guess(cls, no):
if cls.randnum == no:
cls.randnum = randint(1, 1000)
print("New number is ", cls.randnum )
result = True
else:
result = False
return result
def run(self):
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.ip, self.port))
self.server_socket.listen(10)
print('Num is %s' % self.randnum)
while True:
connection, (ip, port) = self.server_socket.accept()
c = Handler(connection, self.randnum)
c.start()
except socket.error as e:
if self.server_socket:
self.server_socket.close()
sys.exit(1)
if __name__ == '__main__':
s = Server('127.0.0.1', 1234)
s.run()