使用asyncio和Python3.6,如何构建一个处理/提交多个顺序请求的TCP服务器/客户端?

使用asyncio和Python3.6,如何构建一个处理/提交多个顺序请求的TCP服务器/客户端?,python,tcp,python-3.6,python-asyncio,Python,Tcp,Python 3.6,Python Asyncio,详情如下: import asyncio @asyncio.coroutine def handle_echo(reader, writer): data = yield from reader.r

详情如下:

import asyncio                                                        

@asyncio.coroutine                                                    
def handle_echo(reader, writer):                                      
    data = yield from reader.read(100)                                
    message = data.decode()                                           
    addr = writer.get_extra_info('peername')                          
    print("Received %r from %r" % (message, addr))                    

    print("Send: %r" % message)                                       
    writer.write(data)                                                
    yield from writer.drain()                                         

    print("Close the client socket")                                  
    writer.close()                                                    

loop = asyncio.get_event_loop()                                       
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8889, loop=loop)
server = loop.run_until_complete(coro)                                

# Serve requests until Ctrl+C is pressed                              
print('Serving on {}'.format(server.sockets[0].getsockname()))        
try:                                                                  
    loop.run_forever()                                                
except KeyboardInterrupt:                                             
    pass                                                              

# Close the server                                                    
server.close()                                                        
loop.run_until_complete(server.wait_closed())                         
loop.close()                                                          
我适应于连续提出两个请求:

import asyncio

async def tcp_echo_client(loop):
    reader, writer = await asyncio.open_connection('127.0.0.1', 8889,
                                                        loop=loop)
    await make_request(reader, writer, "Foo")
    await make_request(reader, writer, "Bar")

    print('Close the socket')
    writer.close()

async def make_request(reader, writer, message):
    print('Send: %r' % message)
    writer.write(message.encode())

    data = await reader.read(100)
    print('Received: %r' % data.decode())

loop = asyncio.get_event_loop()
loop.run_until_complete(tcp_echo_client(loop))
loop.close()
观察到的行为是,客户机获得对第一个请求的响应,但在处理第二个请求之前,套接字已关闭。因此,客户端没有收到对第二个请求的响应

服务器日志:

Received 'Foo' from ('127.0.0.1', 58112)
Send: 'Foo'                             
Close the client socket                 
客户端日志:

Send: 'Foo'
Received: 'Foo'
Send: 'Bar'
Received: ''
Close the socket
所需的行为是客户端接收
Bar
以响应第二个请求,并在请求之间保持套接字打开

如果我注释掉关闭服务器上的套接字,它会阻塞,这样客户机就不会读取对第一个请求的响应,即使缓冲区本应该由
write.drain()
刷新


非常感谢您的指导;提前谢谢。

我想我知道了。查看服务器代码:

  • asyncio.start\u服务器
    不会在其事件循环中重复调用
    handle\u echo
    。我负责在该处理函数中编写一个循环,对每个请求重用
    reader
    writer
  • 而不是抛出异常,
    yield from reader.read(100)
    在客户端关闭其套接字末端后返回0字节
因此,以下是新的服务器代码,它可以按预期工作:

import asyncio

@asyncio.coroutine
def handle_echo(reader, writer):
    while True:
        data = yield from reader.read(100)
        if len(data) > 0:
            message = data.decode()
            addr = writer.get_extra_info('peername')
            print("Received %r from %r" % (message, addr))

            print("Send: %r" % message)
            writer.write(data)
            yield from writer.drain()
        else:
            print("Close the client socket")
            writer.close()
            break

loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8889, loop=loop)
server = loop.run_until_complete(coro)

# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()