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服务器,数据库连接库,分 ...
随机推荐
- BZOJ4025 二分图 线段树分治、带权并查集
传送门 如果边不会消失,那么显然可以带权并查集做(然后发现自己不会写带权并查集) 但是每条边有消失时间.这样每一条边产生贡献的时间对应一段区间,故对时间轴建立线段树,将每一条边扔到线段树对应的点上. ...
- java oop 集合框架
集合主要是用来存放数据的,集合与数组的主要区别在于,集合的大小不受限制,而数组的大小受限制,在使用集合增加数据时又常常与泛型联系起来,所以集合和泛型在实际开发过程中总会结合在一起 数组致命的缺点是数组 ...
- vue脚手架搭建移动端项目--flexible.js
通过命令行 node -v 查看是否安装node环境 在 nodejs 和 webpack已安装的前提下,随便一个文件夹下,输入命令行 npm install vue-cli -g 安装完成后,通过 ...
- java内存模型详解
对于本篇文章,将从四个概念来介绍:内存模型基础,重排序,顺序一致性和happens-before 1.内存模型基础 在并发编程中,有两个关键问题:线程之间如何通信和如何同步.由此而引出了两种并发模型: ...
- Maven将远程包拉去到项目指定路径
<build> <plugins> <plugin> <artifactId>maven-dependency-plugin</artifactI ...
- kettle查询-2
模糊匹配: 1.主数据/查询数据 2.模糊匹配 3.输出:jaro/jaro winkler/pair letters similarity(各自算法的匹配度measure value) http c ...
- SpringBoot 统一时区的方案
系统采用多时区设计的时候,往往我们需要统一时区,需要统一的地方如下: 服务器(Tomcat服务) 数据库(JPA + Hibernate) 前端数据(前端采用Vuejs) 思路为:将数据库和服务器的时 ...
- flex知识点归纳
1.flex-shrink <div id="content"> <div class="box" style="backgroun ...
- springboot 静态注入 单例
package com.b2q.web_push.util; import io.goeasy.GoEasy; import org.springframework.beans.factory.ann ...
- 拷贝文件到服务器 提示FTP文件夹错误
FTP文件夹错误将文件复制到FTP服务器时发生错误.请检查是否有权限将文件放到该服务器上.详细信息:200 Type set to I.227Entering Passive Mode (122,11 ...