Изменить переменную сервера из клиентского потока (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()