前言

本文翻译自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. [Swift]LeetCode685. 冗余连接 II | Redundant Connection II

    In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) f ...

  2. layui.table图片显示不全和404问题

    1.图片显示不全 在使用layui.table组件中,加载的图片显示不全,需重新定义CSS如下: .layui-table-cell{ height: auto!important; white-sp ...

  3. 巡风源码阅读与分析--querylogic函数

    文件位置:views/lib/QueryLogic.py Querylogic() # 搜索逻辑 def querylogic(list): query = {} if len(list) > ...

  4. apollo在liunx环境实战(三)

    1. apollo在liunx环境实战(三) 1.1. 准备 下载apollo源码 https://github.com/ctripcorp/apollo 1.2. 创建数据库 在自己的liunx环境 ...

  5. TDD in .NET Core - 简介

    本文很多内容来自选自TDD实例一书. 预备知识 最好有一些预备知识,例如xUnit,Moq,如何编写易于测试的代码,这些内容我都写了文章:https://www.cnblogs.com/cgzl/p/ ...

  6. IntelliJ IDEA 自定义方法注解模板

    最近没啥事开始正式用Eclipse 转入 idea工具阵营,毕竟有70%的开发者在使用idea开发,所以它的魅力可想而知.刚上手大概有一天,就知道它为啥取名为 intelli(智能化)了,确实很智能, ...

  7. Python内置函数(47)——open

    英文文档: open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, ope ...

  8. C# 《编写高质量代码改善建议》整理&笔记 --(一)基本语言篇

     题记:这是自己的观后感,工作两年了,本来打算好好学习设计模式,或者作为客户端深入了解GPU编程的,但是突然发现还有这么一本书. <编写高质量代码改善建议>,感觉这正是自己需要的. 我是做 ...

  9. redis 系列21 复制Replication (上)

    一.   概述 使用和配置主从复制非常简单,每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave ...

  10. Chapter 5 Blood Type——21

    "Bella." Edward's voice was right beside me, relieved now. "Can you hear me?" “B ...