前言

本文翻译自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. input使用小技巧

    ①:如何修改placeholder样式? input::-webkit-input-placeholder { color: #ccc; font-size: 15px; } 注:其它浏览器适配方案 ...

  2. [Swift]LeetCode49. 字母异位词分组 | Group Anagrams

    Given an array of strings, group anagrams together. Example: Input: ["eat", "tea" ...

  3. iFace安全专家揭秘:存放在区块链钱包中的比特币,其实已经早就不属于你……

    自MoreToken钱包跑路之后,2019年3月以来陆续多个钱包.交易所跑路,造成了大量用户账户被盗,仅MoreToken钱包用户损失总价值就达12.2亿人民币,用户损失惨重.为什么这么多钱包.交易所 ...

  4. Pycharm、IDEA等汉化教程

    本汉化教程对jetbrains全系列可用:IDEA.Pycharm.WebStorm.phpstorm.AndroidStudio.GoLand.RubyMine.CLion 此汉化无副作用,绝对安全 ...

  5. 【Storm篇】--Storm分组策略

    一.前述 Storm由数源泉spout到bolt时,可以选择分组策略,实现对spout发出的数据的分发.对多个并行度的时候有用. 二.具体原理 1. Shuffle Grouping 随机分组,随机派 ...

  6. SpringCloud(8)---zuul权限校验、接口限流

    zuul权限校验.接口限流 一.权限校验搭建 正常项目开发时,权限校验可以考虑JWT和springSecurity结合进行权限校验,这个后期会总结,这里做个基于ZuulFilter过滤器进行一个简单的 ...

  7. vue踩坑--TypeError: __WEBPACK_IMPORTED_MODULE_1_vuex__.a.store is not a constructor

    今天在使用vuex的时候遇到这么个问题,虽然后来解决了,是首字母大写的原因,但我还是不知道为什么.这里先记录下来. 这是vuex/store.js import Vue from 'vue' impo ...

  8. Linq使用Group By

    1.简单形式: var q = from p in db.Products group p by p.CategoryID into g select g; 语句描述:Linq使用Group By按C ...

  9. 如何在.NET Core控制台程序中使用依赖注入

    背景介绍 依赖注入(Dependency Injection), 是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度.在.NET Core MVC中 我们可以在Startup.cs文件的Co ...

  10. asp.net core 系列 4 注入服务的生存期

    一.服务的生存期 在容器中每个注册的服务,根据程序应用需求都可以选择合适的服务生存期,ASP.NET Core 服务有三种生存期配置: (1) Transient:暂时生存期,在每次请求时被创建. 这 ...