前言

本文翻译自python3.7官方文档——asyncio-stream,译者马鸣谦,邮箱 1612557569@qq.com。转载请注明出处。

数据流(Streams)

数据流(Streams)是用于处理网络连接的高阶异步/等待就绪(async/await-ready)原语,可以在不使用回调和底层传输协议的情况下发送和接收数据。

以下是一个用asyncio实现的TCP回显客户端:

import asyncio

async def tcp_echo_client(message):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 8888) print(f'Send: {message!r}')
writer.write(message.encode()) data = await reader.read(100)
print(f'Received: {data.decode()!r}') print('Close the connection')
writer.close()
await writer.wait_closed() asyncio.run(tcp_echo_client('Hello World!'))

完整代码见例子一节。

Stream方法

以下所列的高层asyncio方法可以被用作创建和处理Stream:

  • coroutine asyncio.open_connection(host=None,*,loop=None,limit=None,ssl=None,family=0,proto=0,flags=0,sock=None,local_addr=None,server_hostname=None,ssl_handshake_timeout=None)

    • 创建一个网络连接,并返回一对(reader,writer)对象。
    • 返回的readerwriter对象是StreamReaderStreamWriter类的实例。
    • loop是可选参数,在此方法被某个协程await时能够自动确定。
    • limit限定返回的StreamReader实例使用的缓冲区大小。默认情况下,缓冲区限制为64KiB
    • 其余的参数被直接传递给loop.create_connection()
    • python3.7新增ssl_handshake_timeout参数。
  • coroutine asyncio.start_server(client_connected_cb,host=None,port=None,*,loop=None,limit=None,family=socket.AF_UNSPEC,flags=socket.AI_PASSIVE,sock=None,backlog=100,ssl=None,reuse_address=None,reuse_port=None,ssl_handshake_timeout=None,start_serving=True)

    • 启动一个socket服务端。
    • client_connected_cb指定的回调函数,在新连接建立的时候被调用。该回调函数接收StreamReaderStreamWriter类的‘实例对’(reader,writer)作为两个参数。
    • client_connected_cb可以是普通的可调用函数,也可以是协程函数。如果是协程函数,那么会被自动封装为Task对象处理。
    • loop是可选参数,在此方法被某个协程await时能够自动确定。
    • limit限定返回的StreamReader实例使用的缓冲区大小。默认情况下,缓冲区限定值为64KiB
    • 其余的参数被直接传递给loop.create_server()
    • python3.7新增ssl_handshake_timeoutstart_serving参数。

Unix Sockets

  • coroutine asyncio.open_unix_connection(path=None,*,loop=None,limit=None,ssl=None,sock=None,server_hostname=None,ssl_handshake_timeout=None)

    • 创建一个Unix socket连接,并返回一对(reader,writer)对象。
    • open_connection类似,只是运行在Unix sockets上。
    • 另见loop.create_unix_connection()
    • 可用于:Unix
    • python3.7新增ssl_handshake_timeout参数。
    • python3.7修正path参数可以为类path(path-like)对象
  • coroutine *asyncio.start_unix_server(client_connected_cb, path=None, , loop=None, limit=None, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, start_serving=True)

    • 启动一个Unix socket 服务端。
    • 类似于start_server,只是运行在Unix sockets上。
    • 另见loop.create_unix_server
    • 可用于:Unix
    • python3.7新增ssl_handshake_timeout参数。
    • python3.7修正path参数可以为类path(path-like)对象

StreamReader

class asyncio.StreamReader

定义一个读取器对象,提供从IO数据流中读取数据的API。

不建议 直接实例化StreamReader对象。建议通过open_connection()start_server()创建此类对象。

  • coroutine read(n=-1)

    • 最多读取n字节数据。如果n未设置,或被设置为-1,则读取至EOF标志,并返回读到的所有字节。
    • 如果在缓冲区仍为空时遇到EOF,则返回一个空的bytes对象。
  • coroutine readline()

    • 读取一行(以\n为标志)。
    • 如果在找到\n之前遇到EOF,则返回已读取到的数据段。
    • 如果遇到EOF时内部缓冲区仍为空,则返回空的bytes对象。
  • coroutine readexactly(n)

    • 精确读取n字节数据。
    • 如果在尚未读够n字节时遇到EOF,则引发IncompleteReadError异常。已经读取的部分数据可以通过IncompleteReadError.partial属性获取。
  • coroutine readuntil(separator=b'\n')

    • 从数据流中读取数据直到遇到separator
    • 如果执行成功,读到的数据和分隔符将从内部缓冲区里移除。返回的数据会在末尾包含分隔符。
    • 如果读取数据的总量超过了配置的数据流缓冲区限制,则引发LimitOverrunError,数据会被留在内部缓冲区中,可以被再次读取。
    • 如果在找到separator分隔符之前遇到EOF,则引发IncompleteReadError异常,内部缓冲区会被重置。IncompleteReadError.partial属性会包含部分separator
    • python3.5.2新增。
  • at_eof()

    • 如果缓冲区为空,且feed_eof()被调用,则返回True

StreamWriter

class asyncio.StreamWriter

定义一个写入器对象,提供向IO数据流中写入数据的API。

不建议直接实例化StreamWriter对象,建议通过open_connectionstart_server实例化对象。

  • can_writer_eof()

    • 如果下层传输支持write_eof方法,则返回True,否则返回False
  • write_eof()

    • 在缓冲的写入数据被刷新后,关闭数据流的写入端。
  • transport

    • 返回下层的asyncio传输。
  • get_extra_info(name,default=None)

    • 访问可选的传输信息。
  • write(data)

    • 向数据流中写入数据。
    • 此方法不受流量控制的影响。write()应同drain()一同使用。
  • writelines()

    • 向数据流中写入bytes列表(或任何的可迭代对象)。
    • 此方法不受流量控制的影响。应与drain()一同使用。
  • coroutine drain()

    • 等待恢复数据写入的时机。例如:
    writer.write(data)
    await writer.drain()
    • 这是一个与底层IO输入缓冲区交互的流量控制方法。当缓冲区达到上限时,drain()阻塞,待到缓冲区回落到下限时,写操作可以被恢复。当不需要等待时,drain()会立即返回。
  • close()

    • 关闭数据流。
  • is_closing()

    • 如果数据流已经关闭或正在关闭,则返回True
  • coroutine wait_closed()

    • 保持等待,直到数据流关闭。
    • 保持等待,直到底层连接被关闭,应该在close()后调用此方法。
    • Python3.7新增。

示例

利用Stream实现TCP回显客户端

import asyncio

async def tcp_echo_client(message):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 8888) print(f'Send: {message!r}')
writer.write(message.encode()) data = await reader.read(100)
print(f'Received: {data.decode()!r}') print('Close the connection')
writer.close() asyncio.run(tcp_echo_client('Hello World!'))

利用Stream实现TCP回显服务端

import asyncio

async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername') print(f"Received {message!r} from {addr!r}") print(f"Send: {message!r}")
writer.write(data)
await writer.drain() print("Close the connection")
writer.close() async def main():
server = await asyncio.start_server(
handle_echo, '127.0.0.1', 8888) addr = server.sockets[0].getsockname()
print(f'Serving on {addr}') async with server:
await server.serve_forever() asyncio.run(main())

获取HTTP头

import asyncio
import urllib.parse
import sys async def print_http_headers(url):
url = urllib.parse.urlsplit(url)
if url.scheme == 'https':
reader, writer = await asyncio.open_connection(
url.hostname, 443, ssl=True)
else:
reader, writer = await asyncio.open_connection(
url.hostname, 80) query = (
f"HEAD {url.path or '/'} HTTP/1.0\r\n"
f"Host: {url.hostname}\r\n"
f"\r\n"
) writer.write(query.encode('latin-1'))
while True:
line = await reader.readline()
if not line:
break line = line.decode('latin1').rstrip()
if line:
print(f'HTTP header> {line}') # Ignore the body, close the socket
writer.close() url = sys.argv[1]
asyncio.run(print_http_headers(url))

用法:

python example.py http://example.com/path/page.html

或:

python example.py https://example.com/path/page.html

利用Stream注册等待数据的开放socket

import asyncio
import socket async def wait_for_data():
# Get a reference to the current event loop because
# we want to access low-level APIs.
loop = asyncio.get_running_loop() # Create a pair of connected sockets.
rsock, wsock = socket.socketpair() # Register the open socket to wait for data.
reader, writer = await asyncio.open_connection(sock=rsock) # Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode()) # Wait for data
data = await reader.read(100) # Got data, we are done: close the socket
print("Received:", data.decode())
writer.close() # Close the second socket
wsock.close() asyncio.run(wait_for_data())

asyncio异步IO——Streams详解的更多相关文章

  1. php为什么需要异步编程?php异步编程的详解(附示例)

    本篇文章给大家带来的内容是关于php为什么需要异步编程?php异步编程的详解(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 我对 php 异步的知识还比较混乱,写这篇是为了 ...

  2. java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET

    java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了!      社区福利快来领取免费参加MDCC大会机会哦    Tag功能介绍—我们 ...

  3. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  4. Javascript 异步加载详解

    Javascript 异步加载详解 本文总结一下浏览器在 javascript 的加载方式. 关键词:异步加载(async loading),延迟加载(lazy loading),延迟执行(lazy ...

  5. python中利用队列asyncio.Queue进行通讯详解

    python中利用队列asyncio.Queue进行通讯详解 本文主要给大家介绍了关于python用队列asyncio.Queue通讯的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细 ...

  6. 并发编程——IO模型详解

    ​ 我是一个Python技术小白,对于我而言,多任务处理一般就借助于多进程以及多线程的方式,在多任务处理中如果涉及到IO操作,则会接触到同步.异步.阻塞.非阻塞等相关概念,当然也是并发编程的基础. ​ ...

  7. Java 异步编程 (5 种异步实现方式详解)

    ​ 同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现@mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Comp ...

  8. iostat磁盘IO命令详解

    Linux IO 实时监控iostat命令详解 简介: 对于I/O-bond类型的进程,我们经常用iostat工具查看进程IO请求下发的数量.系统处理IO请求的耗时,进而分析进程与操作系统的交互过程中 ...

  9. 18、标准IO库详解及实例

    标准IO库是由Dennis Ritchie于1975年左右编写的,它是Mike Lestbain写的可移植IO库的主要修改版本,2010年以后, 标准IO库几乎没有进行什么修改.标准IO库处理了很多细 ...

随机推荐

  1. laytpl模板——怎么使用ajax与数据交互

    第一次在项目中用laytpl模板,下面是一些使用过程中的探索,希望对小伙伴们有所帮助. 注:第一次使用这个模板的小伙伴建议先去看看官网 laytpl <script type="tex ...

  2. HBase之行信息简析

    这一节我们简单介绍一下HBase的行信息.文章前半部分会对照源码介绍,后面会有我自己画的图,大家如果对这些信息已经比较了解了,跳过源码对照部分看后面的图,加深一下印象. 下面简单分析一下HBase中对 ...

  3. JavaScript基础之值传递和引用传递

    js的值传递和引用(地址)传递 首先总述一下:js的5种基本数据类型 number,string,null,undefined,boolean 在赋值传递时是值传递,js的引用数据类型(object, ...

  4. oracle调整内存大小

    1.查看已分配内存,看到memory_max_target为20GSQL> show parameter sga NAME                     TYPE     VALUE- ...

  5. Qt之自定义检索框

    1.效果展示 今天这篇文章主要讲解的是自定义搜索框,不仅仅支持搜索,而且可以支持搜索预览,具体请看效果图1.网上也有一些比较简单明了的自定义搜索框,比如Qt之自定义搜索框,讲的也比较详细,不过本文的侧 ...

  6. 阿里云ACE共创空间——MQ消息队列产品测试

    一.产品背景消息队列是阿里巴巴集团自主研发的专业消息中间件. 产品基于高可用分布式集群技术,提供消息订阅和发布.消息轨迹查询.定时(延时)消息.资源统计.监控报警等一系列消息云服务,是企业级互联网架构 ...

  7. ASP.NET Core 2.1 : 十三.httpClient.GetAsync 报SSL错误的问题

    不知什么时候 ,出现了这样的一个奇怪问题,简单的httpClient.GetAsync("xxxx")居然报错了.(ASP.NET Core 系列目录) 一.问题描述 把原来的程序 ...

  8. React-native搭建移动端ios开发环境实践笔记

    开发环境的搭建,按照 https://reactnative.cn/docs/getting-started/ 里面的步骤一步一步来,这里记录下需要注意的几点:1.初始化react-native项目的 ...

  9. 第44章 添加新协议 - Identity Server 4 中文文档(v1.0.0)

    除了对OpenID Connect和OAuth 2.0的内置支持之外,IdentityServer4还允许添加对其他协议的支持. 您可以将这些附加协议端点添加为中间件或使用例如MVC控制器.在这两种情 ...

  10. .net core EFCore CodeFirst 迁移出现错误【No project was found. Change the current working directory or use the --project option. 】

    PM> dotnet ef Migrations add Init No project was found. Change the current working directory or u ...