【问题标题】:Python TCP server accepts new socket, but never receives dataPython TCP服务器接受新套接字,但从不接收数据
【发布时间】:2017-07-17 17:03:46
【问题描述】:

我已经走到了尽头 - 我无法弄清楚这一点。我是 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中看到客户端正在发送消息并且服务器确认它,但它永远不会从recv()返回。

任何帮助将不胜感激。我在很可能是一个简单的错误上浪费了太多时间。

【问题讨论】:

    标签: python multithreading python-3.x sockets tcp


    【解决方案1】:

    self._socket.recv 是一个阻塞调用。它将阻塞,直到它在套接字上接收到数据。我认为问题是:

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

    服务器接收数据但再次进入循环并等待更多数据。退出循环的标准是什么?如果客户端发送数据但没有断开连接,则循环将始终处于活动状态。只有当客户端断开连接时,循环才会中断。

    【讨论】:

      【解决方案2】:

      我相信您自己让事情变得过于复杂。请参阅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
      

      应该注意你的阻塞问题。

      【讨论】:

        猜你喜欢
        • 2015-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-28
        • 2017-06-12
        • 1970-01-01
        • 1970-01-01
        • 2018-11-07
        相关资源
        最近更新 更多