title: Asynchronous socket server with asyncio
body: <p>I want to start an while loop that can only be cancelled when another socket command breaks that loop. I've tried using asyncio but the server doesn't accept incoming messages until the while loop ends/breaks.</p>
  <p>Here is a simplified version of my code that only runs for 5 seconds. After 2 seconds it should cancel the whileLoop function using the <em>&quot;endLoop&quot;</em> message</p>
  <p><strong>server.py</strong></p>
  <pre><code># python 3.7+
  import socket
  import asyncio
  
  class SocketHandler():
      def __init__(self, conn):
          self.conn = conn
          self.run_loop = False
  
      async def recv_loop(self):
          try:
              print('client connected')
              while True:
                  cmd = self.conn.recv(1024)  # receive data from client
                  cmd = cmd.decode()
                  print(cmd)
                  if len(cmd) == 0:
                      break
                  elif cmd == &quot;startLoop&quot;:
                      self.run_loop = True
                      task2 = asyncio.create_task(self.whileLoop())
                      task3 = asyncio.create_task(test_counter())
                      await task2
                      await task3
                  elif cmd == &quot;endLoop&quot;:
                      self.run_loop = False
          finally:
              self.conn.close()
  
      async def whileLoop(self):
          count = 0
          while self.run_loop:
              print('self.run_loop: ' + str(self.run_loop))
              # the below line should allow for other processes to run however
              # 'cmd = self.conn.recv(1024)' only runs after the while loop breaks
              await asyncio.sleep(1)
  
              # break the loop manually after 5 seconds
              count += 1
              if count &gt; 5:
                  break
  
  async def test_counter():
  # just a dummy async function to see if the whileLoop func
  # allows other programs to run
      for k in range(5):
          print(str(k))
          await asyncio.sleep(1)
  
  async def main():
      # this is the main asyncio loop that initializes the socket
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      # sock.setblocking(False)
  
      # Bind the socket to the address given on the command line
      server_address = (&quot;127.0.0.1&quot;, 22000)
      print('starting up on %s port %s' % server_address)
      sock.bind(server_address)
      sock.listen(1)
      while True:
          print('waiting for a connection')
          connection, client_address = sock.accept()
          socketHandler = SocketHandler(connection)
          task1 = asyncio.create_task(socketHandler.recv_loop())  # create recv_loop as a new asyncio task
          await task1
  
  if __name__ == '__main__':
      asyncio.run(main())
  </code></pre>
  <p><strong>client.py</strong></p>
  <pre><code>import time
  import socket
  
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
  sock.connect(('127.0.0.1', 22000))
  
  sock.sendall(b'startLoop')
  time.sleep(2)
  sock.sendall(b'endLoop')
  
  sock.close()
  </code></pre>
  <p>Expected result:</p>
  <pre><code>client connected
  startLoop
  self.run_loop: True
  0
  self.run_loop: True
  1
  self.run_loop: True
  2
  endLoop
  3
  4
  </code></pre>
  <p>Actual results:</p>
  <pre><code>client connected
  startLoop
  self.run_loop: True
  0
  self.run_loop: True
  1
  self.run_loop: True
  2
  self.run_loop: True
  3
  self.run_loop: True
  4
  self.run_loop: True
  endLoop
  </code></pre>