服务端

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协议的更多相关文章

  1. asyncio

    一.简介 asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio的编程模型就是一个消息循环.我们从asyncio模块中直接获取一个EventLoop的引用, ...

  2. 使用asyncio实现redis客户端

    redis协议格式请参考,http://doc.redisfans.com/topic/protocol.html 这里简单介绍下: *<参数数量> \r\n $<参数 的字节数量& ...

  3. asyncio异步IO——Streams详解

    前言 本文翻译自python3.7官方文档--asyncio-stream,译者马鸣谦,邮箱 1612557569@qq.com.转载请注明出处. 数据流(Streams) 数据流(Streams)是 ...

  4. 我实在不懂Python的Asyncio

    原语 事件循环(Event Loop) Awaitables和Coroutines Coroutine Wrappers Awaitables and Futures Tasks Handles Ex ...

  5. 爬虫高性能 asyncio库 twisted库 tornado库

    一 背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行,那只能等待爬取一个结束后才能继续下一个,效率会非常低. 需要强调的是 ...

  6. python之asyncio

    asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asnycio是用来编写并发代码的库,python3.5以后使用async/await语法. asyncio 被用作 ...

  7. (转)asyncio --- 异步 I/O

    原文:https://docs.python.org/zh-cn/3/library/asyncio.html asyncio 是用来编写 并发 代码的库,使用 async/await 语法. asy ...

  8. asyncio并发编程

    一. 事件循环 1.注: 实现搭配:事件循环+回调(驱动生成器[协程])+epoll(IO多路复用),asyncio是Python用于解决异步编程的一整套解决方案: 基于asynico:tornado ...

  9. Python开发【异步】:asyncio

    异步asyncio asyncio是一个使用async / await语法编写并发代码的库. asyncio用作多个Python异步框架的基础,这些框架提供高性能的网络和Web服务器,数据库连接库,分 ...

随机推荐

  1. Linux进程管理专题

    Linux进程管理 (1)进程的诞生介绍了如何表示进程?进程的生命周期.进程的创建等等? Linux支持多种调度器(deadline/realtime/cfs/idle),其中CFS调度器最常见.Li ...

  2. C语言的3种参数传递方式

    参数传递,是在程序运行过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程,方法有3种方式 值传递 地址传递 引用传递 tips: 被调用函数的形参只有函数被调用时 ...

  3. Golang 入门系列(八) cron定时任务

    1.cron 表达式的基本格式  Go 实现的cron 表达式的基本语法跟linux 中的 crontab基本是类似的.cron(计划任务),就是按照约定的时间,定时的执行特定的任务(job).cro ...

  4. Object的所有方法

    Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象.它将返回目标对象. const object1 = { a: 1, b: 2, c: 3 }; const ...

  5. idea在Terminal中使用maven指令

    如果无法直接使用mvn指令,那么这里需要配置你idea中的maven的环境变量, 先说maven在idea中的位置,在你idea安装目录下的\plugins\maven 接下来配置环境变量:在你的用户 ...

  6. Atcoder Beginner Contest 124 解题报告

    心态爆炸.本来能全做出来的.但是由于双开了Comet oj一个比赛,写了ABC就去搞那个的B题 还被搞死了. 回来写了一会D就过了.可惜比赛已经结束了.真的是作死. A - Buttons #incl ...

  7. [BZOJ 3110] [ZJOI 2013] K大数查询

    Description 有 \(N\) 个位置,\(M\) 个操作.操作有两种,每次操作如果是: 1 a b c:表示在第 \(a\) 个位置到第 \(b\) 个位置,每个位置加入一个数 \(c\): ...

  8. JPA 连表查询

    A表和B表 @Entity @Table(name = "A", schema = "kps", catalog = "kps") @Dyn ...

  9. python学习日记(OOP访问限制)

    在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑. 但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的na ...

  10. 【dfs】P1433 吃奶酪

    题目描述 房间里放着n块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处. 输入输出格式 输入格式: 第一行一个数n (n<=15) 接下来每行2个实数,表示第i块 ...