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服务器,数据库连接库,分 ...
随机推荐
- JQuery 获取select 的value值和文本值
<select name="month" id="selMonth"> <option value="1">一 ...
- Redhat6.4安装Oracle 11gr2 64位 注意事项
安装步骤略, 安装步骤参考:https://www.cnblogs.com/jhlong/p/5442459.html 注意的是,会出现找不到一些依赖库,我根据光盘已有的库安装了所有64位的依赖库,强 ...
- 【学习总结】GirlsInAI ML-diary day-17-初始dataframe
[学习总结]GirlsInAI ML-diary 总 原博github链接-day17 认识dataframe 一种非常有用的数据类型,叫做"DataFrame",经常缩写为&qu ...
- Java canlendar task
DayPilot for Java - Calendar, Scheduler and Gantt Chart Componentshttps://java.daypilot.org/ AJAX Sc ...
- Python如何将整数转化成二进制字符串
Python 如何将整数转化成二进制字符串 1.你可以自己写函数采用 %2 的方式来算. >>> binary = lambda n: '' if n==0 else binary( ...
- Error updating database. Cause: java.sql.SQLException: Access denied for user '${username}'@'localhost' (using password: YES)
导入别人的项目,出现一个错误,经过排查,是db.properties配置文件中的用户名与Mybatis-conf.xml配置文件中调用的用户名不一致所导致的 (db.properties中用的是nam ...
- C#中字符串的字面值(转义序列)
在程序开发中,经常会碰到在字符串中字面值中使用转义序列,下面表格收集了下转义序列的完整列表,以便大家查看引用: 转义序列列表 转义序列 产生的字符 字符的Unicode值 \' 单引号 0x0027 ...
- C#、Java和JS实现SHA256+BASE64加密总结
C#.Java和JS实现SHA256+BASE64加密总结 --莫非(www.muphy.me) 原理 首先,通过编码格式(UTF-8.ASCII等,如果含有汉字等字符,编码格式不同加密结果也不同)获 ...
- ZOJ 4097 Rescue the Princess
在这个物欲横流的社会 oj冷漠无情 只有这xx还有些温度 越界就越界吧 wrong 怎么回事.... 给出一个图 然后给出q次询问 问是否存在v和w分别到u的路径且边不重复 在边双连通分量中 任意两 ...
- git 操作命令详解
git 什么是git 开源的分布式版本控制系统, 用于高效的管理大小项目和文件 代码管理工具 防止代码丢失, 做备份 代码版本管控, 设置节点, 多版本切换 建立分支各自开发, 互不影响, 方便合并 ...