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.
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 "endLoop" message
server.py
# 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 == "startLoop":
self.run_loop = True
task2 = asyncio.create_task(self.whileLoop())
task3 = asyncio.create_task(test_counter())
await task2
await task3
elif cmd == "endLoop":
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 > 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 = ("127.0.0.1", 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())
client.py
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()
Expected result:
client connected
startLoop
self.run_loop: True
0
self.run_loop: True
1
self.run_loop: True
2
endLoop
3
4
Actual results:
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
*.pynot*.js... Also -- you don't install asyncio (unless you're using python 3.3 which you're not), it's a stdlib.