lgwest
lgwest

Reputation: 1347

simple python asyncio server does not read data

I am using python3.6 and asyncio on windows10 to make a simple server. I have problem getting the server to work the way I want. But the same server implemented with the socket interface works as expected. Here is the working server

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind(('', 3201))
    s.listen(1)
    conn, addr = s.accept()
    with conn:
        print('Client connection: {}:{}'.format(*addr))
        while True:
            data = conn.recv(1024)
            if data:
                print('recv {} bytes'.format(len(data)))
            else:
                print('no data')
                break
print('connection closed')

I test it with the nc command. e.g.

nc 10.68.100.32 3201
abc
ab
a
^C

The server print:

Client connection: 10.68.101.87:55243
recv 4 bytes
recv 3 bytes
recv 2 bytes
no data
connection closed    

But I can't to do the same server with asyncio. Here is a protocol version:

import asyncio

class ListenServer(asyncio.Protocol):

    def connection_made(self, transport):
        address = transport.get_extra_info('peername')
        print('connection made by client:{}:{}'.format(*address))

    def data_deceived(self, data):
        print('received {}'.format(len(data)), flush=True)

    def eof_received(self):
        print('print received EOF')

    def connection_lost(self, error):
        if error:
            print('ERROR: {}'.format(error))
        else:
            print('connection closed')

event_loop = asyncio.get_event_loop()
factory = event_loop.create_server(ListenServer, '', 3201)
server = event_loop.run_until_complete(factory)

event_loop.run_forever()
print('closing server')
server.close()

For the same nc test sequence as above server writes:

connection made by client:10.68.101.87:55247
print received EOF
connection closed

I also fail with the asyncio coroutine API verion of the server:

import asyncio

async def just_read(reader, writer):
    cli_host, cli_port = writer.get_extra_info('peername')
    print('Client connected {}:{}'.format(cli_host, cli_port))
    while True:
        data = await reader.read()
        if data:
            print('received {} bytes'.format(len(data)), flush=True)
        else:
            print('closing')
            writer.close()
            return

event_loop = asyncio.get_event_loop()
coro = asyncio.start_server(just_read, '', 3201, loop=event_loop)
server = event_loop.run_until_complete(coro)

event_loop.run_forever()
server.close()
print('Connection closed')

The output in this case is a litle differet:

Client connected 10.68.101.87:55253
received 9 bytes
closing

In this case I get all the data when I close down nc with ^C, and the server continues so I can connect again.

I want the server to read and print out what the client writes, it shall connect once and keep the connection as long as the client is connected. How can I achieve this with asyncio, shall I use protocol or coroutine version, does it matter?

And this is only the first, and probably simplest, of several tasks I want the server to do. Other tasks not shown here are start a periodic sending of a dummy message and send response on different messages.

Upvotes: 0

Views: 1677

Answers (1)

user4815162342
user4815162342

Reputation: 155630

The protocol code contains a typo, it names the method data_deceived instead of data_received. Once the method name is corrected, the output becomes the same as in the blocking example.

In the coroutine version, the problem is that reader.read() instructs asyncio to collect the data until end-of-file, and provide it when ready. Changing it to reader.read(1024), in analogy with sock.recv(1024) in the blocking version, fixes the code.

Upvotes: 1

Related Questions