2017-02-27 7 views
0

私は自分のロープの最後です。私はPythonでかなり新しく、私はTCP Server/Clientアプリケーションを書いています。Python TCPサーバーは新しいソケットを受け取りますが、データは受信しません

サーバーは接続をリッスンし、接続を処理するスレッドを生成します。通信は非常にシンプルです - クライアントは接続を行い、メッセージを送信し、サーバーが応答してから接続を閉じます(ala HTTP)

問題は、以下のサーバーコードがクライアントから一貫してデータを受信しないことです。サーバーは新しい接続を受け入れ、新しいスレッドをスピンアップしてから.recvメソッドをブロックします。

サーバリスナ

class TCPListener(threading.Thread): 

    def __init__(self, ip = settings.BIND_IP, port = settings.BIND_PORT): 
     super(TCPListener, self).__init__() 
     self.daemon = True 
     self._port = port 
     self._ip = ip 
     self.stop = threading.Event() 
     self.stop.clear() 

     self.tcp_server_socket = socket(AF_INET, SOCK_STREAM) 
     self.tcp_server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 
     self.tcp_server_socket.setblocking(False) 
     self.tcp_server_socket.bind((self._ip, self._port)) 

    def run(self): 
     # Listen for client connection requests 
     with lock: 
      utils.log_message("Listening for ledger messages on port {0}".format(self._port)) 

     try: 
      self.tcp_server_socket.listen(5) 

      # List for managing spawned threads 
      socket_threads = [] 

      # Non-blocking socket loop that can be interrupted with a signal/event 
      while True and not self.stop.is_set(): 
       try: 
        client_socket, address = self.tcp_server_socket.accept() 

        # Spawn thread 
        client_thread = TCPConnectionThread(client_socket) 
        client_thread.start() 
        socket_threads.append(client_thread) 

       except Exception as e: 
        continue 

      # Clean up all the threads 
      for thread in socket_threads: 
       thread.join() 

     except Exception as e: 
      print("Could not bind to port: {0}".format(e)) 
     finally: 
      self.tcp_server_socket.close() 

サーバー接続ハンドラ

class TCPConnectionThread(threading.Thread): 

    def __init__(self, socket): 
     super(TCPConnectionThread, self).__init__() 
     with lock: 
      utils.log_message("Spawning TCP Connection Thread from {0}".format(socket.getsockname())) 
     self._socket = socket 


    def run(self): 
     # Get message 
     message = '' 
     data = True 
     while data: 
      data = self._socket.recv(4096) #BLOCKS HERE 99% OF THE TIME 
      message+=data.decode() 

     with lock: 
      utils.log_message("Received message from {0}:\n{1}".format(self._socket.getsockname(), message)) 

     self._socket.sendall(response) 
     self._socket.close() 

私のクライアントだけブロックからの接続を処理したスレッド。そのポイント(socket.recv)にブレークポイントを置くと、おそらくデータを受信しますが、通常はそれを実行すると無期限にブロックされます。私はそれがなぜそれに影響を与えるだろうデバッグ、おそらく遅延を導入するかわからない?私はwiresharkでクライアントがメッセージを送信し、サーバがそれをACKしているのを見ることができますが、recv()から返されることはありません。

ご協力いただければ幸いです。私は単純なバグである可能性が最も高いものにあまりにも多くの時間を無駄にしてしまった。

答えて

2

self._socket.recvはブロックコールです。ソケット上のデータを受信するまでブロックされます。

data = True 
while data: 
      data = self._socket.recv(4096) #BLOCKS HERE 99% OF THE TIME 
      message+=data.decode() 

サーバーはデータを受信しますが、再度ループに入り、それ以上のデータを待っています。ループを終了する基準は何ですか?クライアントがデータを送信しても切断しない場合、ループは常にアクティブになります。クライアントが切断した場合のみ、ループが中断します。

0

私はあなた自身が過度に複雑なことをしていると信じています。 Python Cookbookから、次の例を参照してください。

最低で
from socket import AF_INET, SOCK_STREAM, socket 
from concurrent.futures import ThreadPoolExecutor 

def echo_client(sock, client_addr): 
    ''' 
    Handle a client connection 
    ''' 
    print('Got connection from', client_addr) 
    while True: 
     msg = sock.recv(65536) 
     if not msg: 
      break 
     sock.sendall(msg) 
    print('Client closed connection') 
    sock.close() 

def echo_server(addr): 
    print('Echo server running at', addr) 
    pool = ThreadPoolExecutor(128) 
    sock = socket(AF_INET, SOCK_STREAM) 
    sock.bind(addr) 
    sock.listen(5) 
    while True: 
     client_sock, client_addr = sock.accept() 
     pool.submit(echo_client, client_sock, client_addr) 

echo_server(('',15000)) 

この:

while True: 
     msg = sock.recv(65536) 
     if not msg: 
      break 

があなたのブロッキングの問題の世話をする必要があります。

関連する問題