I am trying to listen to a TCP server I have no control over (it is a local windows app broadcasting every 500ms on a fixed socket).
I can set up a reader to get a random length packet in blocking mode
import asyncio, telnetlib3, time
TCP_SERVER_ADDRESS = "127.0.0.7"
TCP_SERVER_PORT = 8000
async def get_one_line(reader):
reply1 = []
while True:
c = await reader.read(1)
if not c:
break
if c in ['\r', '\n']:
break
reply1.append(c)
return reply1
async def main():
reader, writer = await telnetlib3.open_connection(TCP_SERVER_ADDRESS, TCP_SERVER_PORT)
writer.write("$SYS,INFO")
count = 0
while True:
reply = []
reply = await get_one_line(reader)
if reply:
print('reply:', ''.join(reply))
del reply[:]
print(count)
count += 1
if count > 10:
break
time.sleep(0.1)
asyncio.run(main())
and it prints "count" once per TCP packet as expected (sorry about the XXX, not my data)
reply: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2
reply: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3
reply: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4
:
reply: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10
When I tried to wrap get_one_line() in an async function, I wrapped myself firmly around the axle. If I remove the "stop after 10", then it just prints count without receiving anything. If I quit after 10, then all kinds of errors (I assume) because the task was left running.
import asyncio, telnetlib3, time
TCP_SERVER_ADDRESS = "127.0.0.7"
TCP_SERVER_PORT = 8000
async def get_one_line(reader):
reply1 = []
while True:
c = await reader.read(1)
if not c:
break
if c in ['\r', '\n']:
break
reply1.append(c)
return reply1
async def get_nonblocking(reader, callback):
reply2 = await get_one_line(reader)
callback(reply2)
async def main():
reader, writer = await telnetlib3.open_connection(TCP_SERVER_ADDRESS, TCP_SERVER_PORT)
writer.write("$SYS,INFO")
count = 0
while True:
reply = []
getTask = asyncio.create_task(get_nonblocking(reader,reply.append))
if reply:
print('reply:', ''.join(reply))
del reply[:]
print(count)
count += 1
if count > 10:
getTask.cancel()
break
time.sleep(0.1)
asyncio.run(main())
I assume it's that I do not know how to use asyncio and 2 days of reading have not helped. Any help is appreciated.
You say "What I am trying to accomplish it to receive TCP packets while doing other things."
Look at this simpler example:
Example output:
Taking your code, and structuring it similarly:
I can't test this code, since you didn't provide code for the server, but it follows the same pattern.
However, it seems like this would be a bit more straightforward way to go about it:
It should stop after 10 lines have been received, or if the server no longer responds, whatever happens first. There's no need for
while Trueendless loops in both - theget_one_line()generator will keep generating lines as long as we let it. Andcount_lineswill keep reading from it until the counter expires. If you removed the counter, it would just run forever until the task was stopped.Meanwhile,
main()can go do whatever, as long as there's an await in the loop somewhere frequently enough, so that control can pass to the reader.