2015-11-20 5 views
2

Я пишу сетевую гадательную игру, и я мог бы немного помочь с ней. Помимо обработки нескольких клиентов, моему серверу необходимо принять соединение с клиентом администратора. Клиент Admin отображает список IP-адресов и номеров портов клиентов-клиентов, подключенных к серверу. Я понимаю, что для этого нужно реализовать потоки.python threading Guessing game

Вот мой код. Я не уверен, сколько потоков необходимо и как передать информацию подключенных клиентов клиента в поток.

#Server 
import threading 
import socket 
import math 
import random 
import ssl 

def within(guess,goal,n): 
    absValue = abs(guess - goal) 
    if absValue <= n: 
     return True 
    else: 
     return False 

#def HandleAdmin(adminSocket): 
    #(conn,addr) = adminSocket.accept() 
    #ts = ssl.wrap_socket(conn, certfile="5cc515_server.crt", 
          #keyfile="5cc515_server.key", 
          #server_side=True, 
          #cert_reqs=ssl.CERT_REQUIRED, 
          #ca_certs="5cc515-root-ca.cer") 

    #if ts.recv(80).decode() == 'Hello\r\n': 
     #ts.send('Admin-Greetings\r\n'.encode()) 
    #if ts.recv(80).decode() == 'Who\r\n': 
     #ts.send((c,a).encode()) 
    #ts.close() 
    #return 

def HandleClient(c,a): 
    scoreCount = 0 
    guess = 0 
    if(c.recv(80).decode()) == 'Hello\r\n': 
     c.send('Greetings\r\n'.encode()) 

     goal = random.randrange(1,21) 

     while guess!= goal: 
      guess =c.recv(80).decode() 
      guess = int(guess[7:len(guess)-2]) 

      if guess == goal: 
       c.send('Correct\r\n'.encode()) 
      elif within(guess, goal, 2) == True: 
       c.send('Close\r\n'.encode()) 
      else: 
       c.send('Far\r\n'.encode()) 
    c.close() 
    return 

clientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
clientSocket.bind(("127.0.0.1",4000)) 
clientSocket.listen(5) 

adminSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
adminSocket.bind(("127.0.0.1",4001)) 
adminSocket.listen(5) 

while True: 
    (c,a) = clientSocket.accept() 
    #handleAdminThread = threading.Thread(target = AcceptAdminConnection, 
    #          args = adminSocket) 

    clientThread = threading.Thread(target = HandleClient, args = (c,a)) 
    clientThread.start() 

ответ

1

Так вот решение. Он должен работать, но есть к вещам, которые необходимо позаботиться о:

  • вы, вероятно, должны заботиться о вашей связи ПРОТОКОЛ (я не клиентский код здесь, так что я не знать, как он обрабатывает полученные данные ).
  • вам, вероятно, придется добавить несколько циклов для обработки последовательных запросов одного и того же администратора/обычного клиента.

Я не пытался улучшить код, чтобы добавить то, что вы просили, поэтому это может быть не лучшее решение, по крайней мере, оно еще не закончено.

вот как это работает: вы делаете 2 экземпляра TCPServer, один для управления админ-соединением другого для клиентов. Каждый экземпляр имеет BaseRequestHandler.
В основном сервер прослушивает подключения и автоматически запускает новый поток, вызывающий обработчик запросов для каждого из них.

Теперь для обмена данными вы можете использовать любую переменную, здесь словарь и делиться ею между потоками. Установив словарь в качестве члена сервера, вы можете получить доступ к словарю из обработчика запроса. Для защиты доступа к общему диктофону существует блокировка (I.E. мьютекс), она делится как dict.

Вы можете использовать:

комментарий в случае необходимости я буду обновлять.

import threading 
import socketserver 
import ssl 
import random 


class ThreadedTCPAdminRequestHandler(socketserver.BaseRequestHandler): 
    def handle(self): 

     ts = self.request # replaced the ssl connection for simpler code 
     msg = ts.recv(80).decode() 
     # Here should be some kind of loop to be able to handle multiple request of the same admin client 
     # like 'Hello' followed by 'Who' 
     if msg == 'Hello': 
      ts.send('Admin-Greetings\r\n'.encode()) 
     elif msg == 'Who': 
      with self.server.addressesLock: 
       # get a local copy of the dict and quickly release the lock 
       socket_addresses = self.server.addresses.copy() 
      client_string='' 
      # print the list of threads with their address:port 
      for threadName, socket_addresse in socket_addresses.items(): 
       client_string += threadName + ' ' + socket_addresse + '\r\n' 
       # the admin handler doesn't anything if the following line is commented 
       # ts.send(client_string.encode()) 

      # for simpler test, that way you can see the connexion listing is working 
      # even if there are conection problems 
      print(client_string) 
      ts.send('plop'.encode()) 


class ThreadedTCPClientRequestHandler(socketserver.BaseRequestHandler): 
    def handle(self): 
     cur_thread = threading.current_thread().name 
     with self.server.addressesLock: # use a lock to protect the access to the shared dict 
      # add name of the thread ad key and the address:port as value in the global dict 
      self.server.addresses[cur_thread] = self.client_address[0] + ':' + str(self.client_address[1]) 

     score_count = 0 
     guess = 0 
     if (self.request.recv(80).decode()) == 'Hello': 
      self.request.send('Greetings\r\n'.encode()) 

      goal = random.randrange(1, 21) 

      while guess != goal: 
       guess = self.request.recv(80).decode() 
       guess = int(guess[7:len(guess) - 2]) 

       if guess == goal: 
        self.request.send('Correct\r\n'.encode()) 
       elif guess in range(goal-2,goal +2): 
        self.request.send('Close\r\n'.encode()) 
       else: 
        self.request.send('Far\r\n'.encode()) 

     with self.server.addressesLock: # use a lock to protect the access to the shared dict 
      del self.server.addresses[cur_thread] # delete the thread entry in the dict 


class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): 
    pass 


if __name__ == "__main__": 
    C_HOST, C_PORT = 'localhost', 4000 
    A_HOST, A_PORT = 'localhost', 4001 

    clientServer = ThreadedTCPServer((C_HOST, C_PORT), ThreadedTCPClientRequestHandler) 
    adminServer = ThreadedTCPServer((C_HOST, A_PORT), ThreadedTCPAdminRequestHandler) 

    # Start a thread for each the server (client and admin) -- those threads will then start one 
    # more thread for each request 
    clientServer_thread = threading.Thread(target=clientServer.serve_forever) 
    adminServer_thread = threading.Thread(target=adminServer.serve_forever) 

    addresses = {} # create a dict to store the addresses of connected clients 
    addressesLock0 = threading.Lock() # create a lock to protect access to the dict 

    clientServer_thread.daemon = True # client will terminate when main terminate 
    clientServer.addresses = addresses # share the addreses dict 
    clientServer.addressesLock = addressesLock0 # share the lock 
    adminServer_thread.daemon = True 
    adminServer.addresses = addresses 
    adminServer.addressesLock = addressesLock0 

    try: 
     # strart servers 
     clientServer_thread.start() 
     print("clientServer loop running in thread:", clientServer_thread.name) 
     adminServer_thread.start() 
     print("adminServer loop running in thread:", adminServer_thread.name) 

     input('Press Enter to exit...\r\n') # wait input to end the program 

    finally: 
     # stop servers 
     clientServer.shutdown() 
     clientServer.server_close() 
     adminServer.shutdown() 
     adminServer.server_close() 
    exit(0) 
+1

Спасибо, чувак. Я постараюсь понять это и работать с ним завтра. Это может быть немного сложным для моих плохих навыков программирования hehe – Pete

+0

Мне очень жаль, что я не был таким умным, как вы, ребята, но я понятия не имею, как работает этот код. Я прошу прощения. Большое вам спасибо за ваше время. – Pete

+0

Если вы можете дать нам весь код и рассказать нам, что вы не понимаете, мы могли бы вам помочь. – Rbtnk