从客户端线程修改服务器变量(线程,Python)

10

我用Python实现了一个简单的网络“游戏” - 服务器随机生成一个数字,然后客户端尝试猜测它。当客户端猜中数字时,我的应用程序可以正常工作,并与服务器断开连接(由客户端处理)。

然而,在正确猜出数字后,该数字仍然保持不变。我想修改应用程序,使得当客户端猜中数字时,服务器应随机生成一个新数字,以便其他客户端可以猜测新数字。我该如何做到这一点?

以下是一些模板,只是为了引起对问题的注意:

#!/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()

每个客户端应该获得自己的随机数来猜测,还是所有客户端都猜测同一个随机数? - shanmuga
@shanmuga:所有客户端都需要猜测的应该只有一个随机数。当一个客户端猜中时,这个数字应该改变。 - yak
2个回答

3

生成在服务器和所有客户端之间共享的随机数,应该只有一个实例,因此这应该是类属性。
添加一个类函数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函数。

但是当我尝试在服务器端的run方法中打印数字时,我会收到错误提示:NameError: global name 'randnum' is not defined - yak
@yak 有一个错别字(bug)已经被修复。 - shanmuga
然而,当我尝试在服务器的run中执行c = ClientThread(connection, randnum)时,它显示了我之前发布的错误。也许我做错了什么? - yak
你应该使用 self.randnum 来访问它,就像你在问题中展示的那样。 - shanmuga
然后我又遇到了另一个错误,靠近 if cls.randnum == no:,即:AttributeError: class Server has no attribute 'randnum' - yak
显示剩余3条评论

1
实际上,您的问题源于将randnum创建为实例方法(请参见self.randnum),如@shanmuga所解释的那样,如果您只是将其声明为类属性并删除实例方法,则可以解决您的问题(即在类中直接声明)。
作为一个次要问题(不是socket专家),当您向客户端发送消息时,您可能希望将它们编码为字节对象(在Handler的run方法中,我将self.connection.send(msg)更改为self.connection.send(msg.encode()))。另外请注意,我使用的是Python 3.6版本(主要更改了print语句的样式)。
请参见下面的代码:
#!/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()

抱歉我忘记了赏金。但我认为我的问题比Python更普遍。如何在Java、C++、C等语言中实现相同的功能呢?问题是:当客户端需要向服务器发送消息时,我总是遇到一个问题,而服务器则应该结束其工作等。 - yak
@yak 许多问题可能会发生(网络丢失、消息处理错误等)。我认为你的设计中一个问题是将类方法和实例方法分开。例如,我认为 randint 应该属于你的 Server 实例,因为它是该实例状态的一部分,并且必须在任何客户端找到后进行修改。每次需要修改 Server 实例的状态(例如关闭它)时,应该使用实例方法。你可以使用 classmethod 来使其工作,但这可能不太优雅。 - Adonis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接