asyncio协议
服务端
import asyncio
import logging
import sys
from typing import Optional
SERVER_ADDRESS = ('localhost', 10000)
logging.basicConfig(
level=logging.DEBUG,
format='%(name)s: %(message)s',
stream=sys.stderr,
)
log = logging.getLogger('main')
class EchoServer(asyncio.Protocol):
"""
每个新客户端连接都会触发对connection_made()的调用。
transport参数是asyncio.Transport的一个实例,它提供了使用套接字进行异步I/O的抽象。
不同类型的通信提供不同的传输实现,所有这些都具有相同的API。
例如,有单独的传输类用于处理套接字和处理管道到子进程。
传入客户端的地址可通过get_extra_info()传输获得,
get_extra_info()是一种特定于实现的方法。
启动顺序
State machine of calls:
start -> CM [-> DR*] [-> ER?] -> CL -> end
* CM: connection_made()
* DR: data_received()
* ER: eof_received()
* CL: connection_lost()
"""
def connection_made(self, transport):
self.transport = transport
self.address = transport.get_extra_info('peername')
self.log = logging.getLogger('EchoServer_{}_{}'.format(*self.address))
self.log.debug('connection accepted')
def data_received(self, data: bytes) -> None:
"""
类似于一个循环,循环调用这个方法读取内容。
"""
self.log.debug('received{!r}'.format(data))
self.transport.write(data)
self.log.debug('sent {!r}'.format(data))
def eof_received(self) -> Optional[bool]:
"""
有些传输支持特殊的文件结束指示符(“EOF”)。
遇到EOF时,调用eof_received()方法。在这个实现中,
EOF被发送回客户端以指示它被接收到。
因为不是所有的传输都支持显式的EOF,
所以该协议首先询问传输发送EOF是否安全。
:return:
"""
self.log.debug('received EOF')
if self.transport.can_write_eof():
self.transport.write_eof()
def connection_lost(self, exc: Optional[Exception]) -> None:
"""
当连接关闭时,无论是正常情况还是由于错误,
都会调用协议的connection_lost()方法。
如果有错误,参数包含适当的异常对象。否则就没有了。
:param exc:
:return:
"""
if exc:
self.log.error('ERROR:{}'.format(exc))
else:
self.log.debug('closing')
super().connection_lost(exc)
if __name__ == '__main__':
"""
然后需要运行事件循环以处理事件和处理客户端请求。
对于长时间运行的服务,run_forever()方法是执行此操作的最简单方法。
当事件循环被应用程序代码或通过发送进程信号停止时,
可以关闭服务器以正确清理套接字,
然后可以关闭事件循环以在程序退出之前完成处理任何其他协同程序。
"""
loop = asyncio.get_event_loop()
factory = loop.create_server(EchoServer, *SERVER_ADDRESS)
server = loop.run_until_complete(factory)
log.debug('starting up on {} port {}'.format(*SERVER_ADDRESS))
try:
loop.run_forever()
finally:
log.debug('closing server')
server.close()
loop.run_until_complete(server.wait_closed())
log.debug('closing event loop')
loop.close()
客户端
import asyncio
import functools
import logging
import sys
from asyncio import transports
from typing import Optional
MESSAGES = [
b'This is the message. ',
b'It will be sent ',
b'in parts.',
]
SERVER_ADDRESS = ('localhost', 10000)
logging.basicConfig(
level=logging.DEBUG,
format='%(name)s: %(message)s',
stream=sys.stderr,
)
log = logging.getLogger('main')
event_loop = asyncio.get_event_loop()
class EchoClient(asyncio.Protocol):
"""
客户机协议类定义了与服务器相同的方法,但实现不同。
类构造函数接受两个参数,一个是要发送的消息列表,
另一个是将来要使用的实例,通过接收来自服务器
的响应来表示客户机已经完成了一个工作周期。
"""
def __init__(self, messages, future):
super().__init__()
self.messages = messages
self.log = logging.getLogger('EchoClient')
self.f = future
def connection_made(self, transport: transports.BaseTransport) -> None:
self.transport = transport
self.address = transport.get_extra_info('peername')
self.log.debug('connecting to {} port {}'.format(*self.address))
for msg in self.messages:
transport.write(msg)
self.log.debug('sending {!r}'.format(msg))
if transport.can_write_eof():
transport.write_eof()
def data_received(self, data: bytes) -> None:
self.log.debug("received {!r}".format(data))
def eof_received(self) -> Optional[bool]:
self.log.debug('received EOF')
self.transport.close()
if not self.f.done():
self.f.set_result(True)
def connection_lost(self, exc: Optional[Exception]) -> None:
self.log.debug('server closed connection')
self.transport.close()
if not self.f.done():
self.f.set_result()
super().connection_lost(exc)
client_completed = asyncio.Future()
client_factory = functools.partial(
EchoClient,
messages=MESSAGES,
future=client_completed,
)
factory_coroutine = event_loop.create_connection(
client_factory,
*SERVER_ADDRESS,
)
log.debug('waiting for client to complete')
try:
event_loop.run_until_complete(factory_coroutine)
event_loop.run_until_complete(client_completed)
finally:
log.debug('closing event loop')
event_loop.close()
asyncio协议的更多相关文章
- asyncio
一.简介 asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio的编程模型就是一个消息循环.我们从asyncio模块中直接获取一个EventLoop的引用, ...
- 使用asyncio实现redis客户端
redis协议格式请参考,http://doc.redisfans.com/topic/protocol.html 这里简单介绍下: *<参数数量> \r\n $<参数 的字节数量& ...
- asyncio异步IO——Streams详解
前言 本文翻译自python3.7官方文档--asyncio-stream,译者马鸣谦,邮箱 1612557569@qq.com.转载请注明出处. 数据流(Streams) 数据流(Streams)是 ...
- 我实在不懂Python的Asyncio
原语 事件循环(Event Loop) Awaitables和Coroutines Coroutine Wrappers Awaitables and Futures Tasks Handles Ex ...
- 爬虫高性能 asyncio库 twisted库 tornado库
一 背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行,那只能等待爬取一个结束后才能继续下一个,效率会非常低. 需要强调的是 ...
- python之asyncio
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asnycio是用来编写并发代码的库,python3.5以后使用async/await语法. asyncio 被用作 ...
- (转)asyncio --- 异步 I/O
原文:https://docs.python.org/zh-cn/3/library/asyncio.html asyncio 是用来编写 并发 代码的库,使用 async/await 语法. asy ...
- asyncio并发编程
一. 事件循环 1.注: 实现搭配:事件循环+回调(驱动生成器[协程])+epoll(IO多路复用),asyncio是Python用于解决异步编程的一整套解决方案: 基于asynico:tornado ...
- Python开发【异步】:asyncio
异步asyncio asyncio是一个使用async / await语法编写并发代码的库. asyncio用作多个Python异步框架的基础,这些框架提供高性能的网络和Web服务器,数据库连接库,分 ...
随机推荐
- C# — 实现软件开机自启功能(不需要管理员权限)
因为最近项目需要,昨晚花了2个小时的时间,在网上搜索资料,通过C#实现了程序开机自启的功能,思路是:将软件的快捷方式创建到计算机的自动启动目录下就行了. 1.新建一个控制台项目:AutoStart 2 ...
- Gdi绘图
在使用VC开发项目过程中,界面是项目中的一个子模块.虽然界面并不那么重要,把握住核心功能就可以了,但界面美观与否直接关系到用户的体验, 因此我们也应该关注界面的处理. 我们可以在OnEraseBkgn ...
- WPF: 自动设置Owner的ShowDialog 适用于MVVM
原文:WPF: 自动设置Owner的ShowDialog 适用于MVVM 原文地址:http://www.mgenware.com/blog/?p=339 WPF中的Windows的ShowDialo ...
- python部署galery集群
galery.py文件内容 import pexpect import os import configparser HOSTNAME_DB1='db1' HOSTNAME_DB2='db2' HOS ...
- Python之find命令中的位置的算法
find("s",a,b) #s表示的是一个子序列,a表示的是检索的起始位置,b表示的是检索的终止位置,ab可有可无 test = "abcdefgh" ...
- synchronized详解
关于synchronized,本文从使用方法,底层原理和锁的升级优化这几个方面来介绍. 1.synchronized的使用: synchronized可以保证在同一时刻,只有一个线程可以操作共享变量, ...
- 【题解】放球游戏A
题目描述 校园里在上活动课,Red和Blue两位小朋友在玩一种游戏,他俩在一排N个格子里,自左到右地轮流放小球,每个格子只能放一个小球.每个人一次只能放1至5个球,最后面对没有空格而不能放球的人为输. ...
- 【ARC101F】Robots and Exits 树状数组
题目大意 有 \(n\) 个机器人和 \(m\) 个出口. 这 \(n\) 个机器人的初始位置是 \(a_1,a_2,\ldots,a_n\),这 \(m\) 个出口的位置是 \(b_1,b_2,\l ...
- PHP 5.6 中 Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version
解决方法 找到php.ini 文件, 把always_populate_raw_post_data 修改为-1 就行了. always_populate_raw_post_data=-1
- CSS当中数学表达式calc
CSS当中数学表达式calc 数学表达式calc()是CSS中的函数,主要用于数学运算.使用calc()为页面元素布局提供了便利和新的思路.本文将介绍calc()的相关内容 定义 数学表达式calc ...