2017-05-03 9 views
10

私はPythonで単純なネットワーク 'game'を実装しました - サーバは乱数を描画し、クライアントはそれを推測しようとします。私のアプリケーションは素晴らしいです。クライアントが番号を推測すると、サーバーから切断されます(クライアントの側で処理されます)。クライアントのスレッドからサーバの変数を変更する(スレッド、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

:また、私は(主にprint文のスタイルを変更)はPython 3.6

は、以下のコードを参照してください使用していることに注意してくださいすべてのクライアントが推測する1つの乱数? – shanmuga

+0

@shanmuga:すべてのクライアントが推測する必要がある乱数は1つだけです。 1つのクライアントがそれを推測するときに番号が変わるはずです。 – yak

答えて

3

は、サーバーとすべてのクライアントの両方の間で共有される乱数を生成し、これの唯一のインスタンスをそこにする必要があります、したがって、これはする必要がありますクラス属性。
間違って推測すると、正しい推測するとFalseを返すどのクラス機能guessを追加し、クライアントがこのServer.guess機能を毎回呼び出す必要があり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): 
     # ... 

を返します。

+0

しかし、 'run'メソッドでサーバー側の数値を表示しようとすると、' NameError:グローバル名 'randnum'が定義されていません。 'というエラーが出ます。 – yak

+0

@yak誤字が修正されました。 – shanmuga

+0

でも、例えばサーバの 'run'で' c = ClientThread(connection、randnum) 'を実行しようとすると、以前に投稿したエラーが表示されます。たぶん私は何か悪いことをするでしょうか? – yak

1

実際には、あなたが単純にクラス属性として宣言し、問題を解決するインスタンスメソッドを削除した場合、@shanmugaが説明したように、インスタンスメソッド(self.randnumを参照)としてrandnumを作成するという事実が原因ですつまり、クラス内で直接宣言します)。側の問題(ソケットの専門家されていない)として

、あなたがクライアントにメッセージを送信するとき、あなたはバイトのオブジェクトとしてそれらをコードする場合があります(ハンドラのrun方法で、私はself.connection.send(msg.encode())self.connection.send(msg)を変更)。各クライアントは、それは推測する必要がある、または唯一の存在であることを、独自の乱数を取得する必要があります

#!/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多くの問題が発生する可能性があります(ネットワークの紛失、メッセージの誤った処理...私はあなたのデザインの問題の1つは、クラスメソッドとインスタンスメソッドを分離すると考えています。たとえば、 'randint'はこのインスタンスの状態の一部としてサーバーインスタンスに属している必要があり、一度クライアントが見つけたら変更する必要があると思います。サーバーインスタンスの状態を変更する必要があるたびに(インスタンスを閉じるなど)、インスタンスメソッドにする必要があります。あなたはクラスメソッドで動作させることができますが、おそらくエレガントではありません。 – Adonis

関連する問題