2017-05-03 81 views
10

我在Python中实现了一个简单的网络'游戏' - 服务器绘制一个随机数,然后客户端试图猜测它。我的应用程序工作得很好,当客户端猜测数字时,它会与服务器断开连接(它在客户端处理)。修改客户端线程的服务器变量(线程,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() 
+0

如果每个客户获得自己的随机数,它应该猜到,还是应该只有所有客户都会猜测一个随机数字? – shanmuga

+0

@shanmuga:应该只有一个随机数,所有客户需要猜测。当一个客户猜测它时,该数字应该改变。 – yak

回答

3

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

+0

但是,当我尝试在'run'方法中在服务器端打印数字时,出现错误:'NameError:全局名称'randnum'未定义' – yak

+0

@yak修复了错误(错误)。 – shanmuga

+0

然而,当我尝试,例如,在服务器的'run'中执行'c = ClientThread(connection,randnum)',它显示了我之前发布的错误。也许我做错了什么? – yak

1

其实你的问题来自于您创建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() 
+0

对不起,我忘记了赏金。但我认为我的问题比Python更普遍。在Java,C++,C等中如何实现相同的功能?问题是:当客户端需要通过消息通知服务器时,我总是有问题,然后服务器应该例如结束工作。 – yak

+0

@ yak可能会发生许多问题(网络丢失,消息处理错误...等等)我相信你的设计中的一个问题是分离类方法和实例方法。例如,我认为'randint'应该属于你的服务器实例,因为它是这个实例状态的一部分,并且只要任何客户端发现它就必须修改。每次需要修改服务器实例的状态(例如关闭它)时,它应该是一个实例方法。你可以使用classmethod工作,但它可能不会很优雅。 – Adonis

相关问题