2017-05-03 57 views
10

Python'da basit bir ağ 'oyunu' uyguladım - sunucu rastgele bir sayı çiziyor ve sonra istemci bunu tahmin etmeye çalışıyor. Uygulamam, müşteri sayıyı tahmin ettiğinde harika çalışıyor, sunucudan ayrılıyor (istemci tarafında ele alınmaktadır). Ancak, doğru tahminden sonra, sayı hala aynıdır. Uygulamayı değiştirmek istiyorum, böylece müşteri sayıyı tahmin ettiğinde, sunucu yeni bir numara atamalı, böylece diğer müşteriler yeni bir tane tahmin etmelidir. Bunu nasıl yapabilirim?İstemcinin iş parçacığından (threading, python) sunucunun değişkenini değiştirin

Bazı şablon, sadece soruna bir dikkat çekmek için:

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

her istemci tahmin gerektiğini kendi rastgele sayı elde mıdır veya sadece olmalı tüm müşterilerin tahmin edeceği bir rasgele sayı? – shanmuga

+0

@shanmuga: Tüm müşterilerin tahmin etmesi gereken yalnızca bir rastgele sayı olmalıdır. Bir müşteri bunu tahmin ettiğinde sayı değişmelidir. – yak

cevap

3

sunucu ve tüm istemci hem arasında paylaşılır rastgele sayı üret, bu sadece bir örneğini olmalı, dolayısıyla bu olmalı sınıf özniteliği.
doğru tahmin randnum değiştirir ve istemci her zaman bu Server.guess işlevini çağırmalıdır 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): 
     # ... 

döndürür yanlış tahmin üzerine ve üzerine False geri verdiğiniz sınıf işlevini guess ekleyin.

+0

Numarayı sunucu tarafında "run" yönteminde yazdırmaya çalıştığımda, hatayı alıyorum: 'NameError: global name 'randnum' tanımlı değil ' – yak

+0

@yak Bir yazım hatası (hata) düzeltildi. – shanmuga

+0

Yine de, örneğin, sunucunun 'run' do' c = ClientThread (bağlantı, randnum) 'da denediğimde, daha önce gönderdiğim hatayı gösterir. Belki yanlış bir şey yapıyorum? – yak

1

Aslında, sorununuz yalnızca bir sınıf özniteliği olarak bildirirseniz ve örnek yöntemini kaldırırsanız sorununuzu çözdüğünüzden (örnek: self.randnum) örnek yöntem olarak randnum oluşturduğunuzdan kaynaklanır. yani doğrudan sınıfta beyan etmek). Bir yan konuya olarak

Eğer müşteriye mesaj göndermek zaman, bir bayt nesnesi olarak bunları kodlamak isteyebilirsiniz (soket üzerinde bir uzman olmayan) (Besleyicisi'nin run yönteminde, ben self.connection.send(msg.encode()) için self.connection.send(msg) değişti). Ayrıca ben

Aşağıdaki kod bakın (özellikle baskı tabloların stilini değiştirmek) Python 3.6 kullandığını belirtelim:

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

Üzgünüm, kelle hakkında unuttum. Ama bence sorunum Python'dan daha genel. Java, C++, C vb. Ile aynı şey nasıl uygulanabilir? Soru şudur: İstemcilerin bir iletiyi bir sunucuya bildirmesi gerektiğinde her zaman bir sorun yaşıyorum ve sunucu örneğin çalışmayı bitirmelidir. – yak

+0

@yak Pek çok sorun meydana gelebilir (ağ kaybı, mesajların yanlış işlenmesi ...vb) Tasarımınızdaki sorunlardan birinin sınıf yöntemini ve örnek yöntemlerini ayırdığına inanıyorum. Örneğin, "randint" in, bu örneğinin bir parçası olduğu ve herhangi bir istemci tarafından bulunduğunda değiştirilmek zorunda olduğu için Sunucu örneğinize ait olması gerektiğini düşünürdüm. Sunucu örneğinizin durumunu değiştirmek için her zaman (örneğin, kapatmak), bir örnek yöntemi olmalıdır. Bir classmethod ile çalışabilirsiniz, ama muhtemelen zarif olmaz. – Adonis