2017-01-22 13 views
0

私はいくつかのRaspberry Pis、Python、いくつかのボタン/スイッチを使ってゲームを行ってきました。私のゲームでは、複数のクライアントにコマンドを発行する中央サーバーが必要です。Python TCP Server接続とブロードキャストコマンドを受け入れる

私はプログラミングには新しくないが、Pythonや低レベルのネットワーク通信には新しくなく、サーバーコードの正確な記述方法について過去2日間は雑草で失われている。

クライアントプログラムは単純なsocket.connectで、データの送信を待機します。そこに問題はありません。

私は、サーバーの作成方法と作成方法を正確に判断するのに苦労しました。ここで

は私のサーバーコードは、現時点では次のようになります。 1.サーバーが起動して待機最初の接続以上:

import socket, time, sys 
import threading 

TCP_IP = '' 
TCP_PORT = 8888 
BUFFER_SIZE = 1024 
CLIENTS = {} 
clientCount = 0 

def listener(): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.bind((TCP_IP,TCP_PORT)) 
    s.listen(5) 
    while True: 
     conn, addr = s.accept() 
     print("new connection from:"+ str(addr)) 
     #print(len(CLIENTS)) 
     global clientCount 
     clientCount = clientCount+1 
     print (clientCount) 
     # register client 
     CLIENTS[conn.fileno()] = conn 


def broadcast(): 
    for client in CLIENTS.values(): 
      client.send('this is a broadcats msg') 

if __name__ == '__main__': 
    listener() 

    while clientCount > 0: 
     broadcast() 
     print(len(CLIENTS)) #print out the number of connected clients every 5s 
     time.sleep(5) 

ここで所望の流れです。私はこの "サーバ"はバックグラウンドスレッドで実行されるべきだと思いますか? 2. connectionCount > 0がメインプログラムループを開始する場合 3.メインプログラムループは、接続されたクライアントの数を表示し、5秒ごとにすべてのクライアントにメッセージをブロードキャストするだけです。

私はこのサーバーのバージョンが約5つあります。私は非同期、select.select、およびいくつかのスレッド・アプローチを試みましたが、私が求めている振る舞いを釘付けにすることはできません。サーバーをバックグラウンドスレッドにする必要がありますか?もしそうなら、どのようにすべての接続にブロードキャストするのですか?

私が試したことのない唯一のことは、ツイストされています。なぜなら、それはWindowsにインストールされていなかったからです...私はそのoptinoを現時点で支配しています。誰かがこれに行く場所にポインタを持っているなら、私は本当にそれを感謝します!

更新

[OK]を、@Armansの提案に基づいてサーバクラスがあるように私は自分のコードを更新したが、それはまだ同じことを実行します。

class server(): 

    def __init__(self): 
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     s.bind((TCP_IP,TCP_PORT)) 
     s.listen(10) 
     while 1: 
      client_socket, addr = s.accept() 
      print ('Connected with ' + addr[0] + ':' + str(addr[1])) 
      global clientCount 
      clientCount = clientCount+1 
      print (clientCount) 
      # register client 
      CLIENTS[client_socket.fileno()] = client_socket 
      threading.Thread(target=self.handler, args=(client_socket, addr)).start() 



    def handler(self, client_socket, addr): 
     while 1: 
      data = client_socket.recv(BUFFER_SIZE) 
      print ('Data : ' + repr(data) + "\n") 
      data = data.decode("UTF-8") 


    def broadcast(self, message): 
     for c in self.CLIENTS: 
      c.send(message.encode("utf-8")) 

if __name__ == '__main__': 
    s = server() #create new server listening for connections 

    while clientCount > 0: 
     s.broadcast('msg here') 
     print(len(CLIENTS)) #print out the number of connected clients every 5s 
     time.sleep(5) 

私は複数のクライアントを接続することができ、コンソールには次のように表示されます。

Connected with 10.0.0.194:38406 
1 
Connected with 10.0.0.169:36460 
2 

しかし、「しばらくclientCount」ループが実行されることはありませんのコード。これは私がしばらくの間立ち往生していたゾーンなので、ここに何か考えてみたいと思っています。

答えて

0

最後にそれは働いた! @Armanはスレッドを使って正しい方向に向いてくれてとても感謝しています。私は最終的にすべての仕組みが分かっているように感じます!

私の完全なサーバー&クライアントコードです。うまくいけば、これはマスター>クライアントのセットアップで他の誰かを助けるでしょう。 _broadcast()関数は、現時点で静的メッセージをブロードキャストするだけであることがわかりますが、簡単に更新できるはずです。

誰かがコードのクリーンアップに関するアドバイスをお持ちの場合は、このコードをサンプルとして使用して、Pythonのベストプラクティスを聞き、もっと勉強したいと思います。もう一度SEに感謝!

##Client 

import socket 
import sys 
import json 

#vars 
connected = False 

#connect to server 
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
client_socket.connect(('10.0.0.158',8888)) 
connected = True 

while connected == True: 
    #wait for server commands to do things, now we will just display things 
    data = client_socket.recv(1024)  
    cmd = json.loads(data) #we now only expect json  
    if(cmd['type'] == 'bet'): 
     bet = cmd['value'] 
     print('betting is: '+bet) 
    elif (cmd['type'] == 'result'):   
     print('winner is: '+str(cmd['winner'])) 
     print('payout is: '+str(cmd['payout'])) 


##Server 

import socket, time, sys 
import threading 
import pprint 

TCP_IP = '' 
TCP_PORT = 8888 
BUFFER_SIZE = 1024 

clientCount = 0 

class server(): 

    def __init__(self): 
     self.CLIENTS = []   


    def startServer(self): 
     try: 
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      s.bind((TCP_IP,TCP_PORT)) 
      s.listen(10) 
      while 1: 
       client_socket, addr = s.accept() 
       print ('Connected with ' + addr[0] + ':' + str(addr[1])) 
       global clientCount 
       clientCount = clientCount+1 
       print (clientCount) 
       # register client 
       self.CLIENTS.append(client_socket) 
       threading.Thread(target=self.playerHandler, args=(client_socket,)).start() 
      s.close() 
     except socket.error as msg: 
      print ('Could Not Start Server Thread. Error Code : ') #+ str(msg[0]) + ' Message ' + msg[1] 
      sys.exit() 


    #client handler :one of these loops is running for each thread/player 
    def playerHandler(self, client_socket): 
     #send welcome msg to new client 
     client_socket.send(bytes('{"type": "bet","value": "1"}', 'UTF-8')) 
     while 1: 
      data = client_socket.recv(BUFFER_SIZE) 
      if not data: 
       break 
      #print ('Data : ' + repr(data) + "\n") 
      #data = data.decode("UTF-8") 
      # broadcast 
      for client in self.CLIENTS.values(): 
       client.send(data) 

     # the connection is closed: unregister 
     self.CLIENTS.remove(client_socket) 
     #client_socket.close() #do we close the socket when the program ends? or for ea client thead? 

    def broadcast(self, message): 

     for c in self.CLIENTS: 
      c.send(message.encode("utf-8")) 

    def _broadcast(self):   
     for sock in self.CLIENTS:   
      try : 
       self._send(sock) 
      except socket.error:     
       sock.close() # closing the socket connection 
       self.CLIENTS.remove(sock) # removing the socket from the active connections list 

    def _send(self, sock):   
     # Packs the message with 4 leading bytes representing the message length 
     #msg = struct.pack('>I', len(msg)) + msg 
     # Sends the packed message 
     sock.send(bytes('{"type": "bet","value": "1"}', 'UTF-8')) 


if __name__ == '__main__': 
    s = server() #create new server listening for connections 
    threading.Thread(target=s.startServer).start() 

    while 1:  
     s._broadcast() 
     pprint.pprint(s.CLIENTS) 
     print(len(s.CLIENTS)) #print out the number of connected clients every 5s 
     time.sleep(5) 
0

私はここにmultithreadアプローチを持っている:

s.listen(10) 
    while 1: 
     client_socket, addr = s.accept() 
     print ('Connected with ' + addr[0] + ':' + str(addr[1])) 
     threading.Thread(target=self.handler, args=(client_socket, addr)).start()   


def handler(self, client_socket, addr): 
    while 1: 
     data = client_socket.recv(BUFF) 
     print ('Data : ' + repr(data) + "\n") 
     data = data.decode("UTF-8") 

私は強くあなたは、2つの(各クライアントのクライアントobjectを作成し、Serverに接続し、ServerClientのためのクラスを作成し、各接続クライアントを保存をお勧めしますそのソケットと名前など)を辞書に追加すると、接続されているすべてのクライアントを経由してServerというメッセージをブロードキャストし、次のようなメッセージをブロードキャストできます。

def broadcast(self, client_socket, message): 
     for c in self.clients: 
      c.send(message.encode("utf-8")) 
あなたがメインに実行 threadは、サーバーを実行するための別の threadを必要としていますので

更新

、私はあなたがサーバのstart方法を記述し示唆してthreadでそれを呼び出す:今

def start(self): 
    # all server starts stuff comes here as define socket 
    self.s.listen(10) 
    while 1: 
     client_socket, addr = self.s.accept() 
     print ('Connected with ' + addr[0] + ':' + str(addr[1])) 
     threading.Thread(target=self.handler, args=(client_socket, addr)).start() 

メインセクションまたはメインファイル内のサーバーオブジェクトの作成後に開始スレッドを実行:

a = server() 
threading.Thread(target=a.start).start() 
関連する問題