使用 asyncio streams 编写 TCP 客户端和服务端的程序
回显: 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())
await writer.drain()
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!'))
服务端
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())
首先 要把代码跑起来,然后我们再了解这些asyncio stream 这些api的意思
首先来看服务端用到的API
<1> 服务端创建并启动一个套接字 asyncio.start_server
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)
当有新的客户端 连接被建立的时候,回自动回调 client_connected_cb,该函数有2个参数,
(reader, writer),reader是类 StreamReader 的实例,而writer是类 StreamWriter 的实例
client_connected_cb 即可以是普通的可调用对象也可以是一个 协程函数; 如果它是一个协程函数,它将自动作为 Task 被调度。
limit 确定返回的 StreamReader 实例使用的缓冲区大小限制。默认情况下,limit 设置为 64 KiB 。
loop 参数是可选的。当在一个协程中await该方法时,该参数始终可以自动确定。
<2> 建立网络连接 asyncio.open_connection
coroutine asyncio.open_connection(host=None, port=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) 对象。
<3> reader 和 writer
然后我们再来看返回的两个类的实例 如何使用
reader是类 StreamReader 的实例,而writer是类 StreamWriter 的实例。
看名字就知道了,reader 是从io流中读取数据。
read( n= -1 )
n ,读取n个byte并返回
默认为-1,则读取至EOF,并返回所有读取到的byte
如果读取到EOF,且内部缓冲区为空,则返回空的bytes对象
readline()
读取一行,\n 结尾为一行。
如果读到EOF而没有\n 则返回部分读取的数据
如果读取到EOF,且内部缓冲区为空,则返回空的bytes对
readexactly(n)
精确读取n个byte,不能多也不能少
可以使用 IncompleteReadError.partial 属性来获取到达流结束之前读取的 bytes 字符串
readuntil(separator=b’\n’)
从流中读取数据,直到遇到指定的分隔符,返回数据包括指定的分隔符
如果读取的数量,超过配置的流限制,则引发异常 IncompleteReadError ,并重置缓冲区。
at_eof()
如果缓冲区为空并且 feed_eof() 被调用,则返回 True 。
writer,向io流中写入数据
write(data)
写入数据,一般与 drain() 一起使用
writelines(data)
写入的data,必须是一个字节列表,一样的 一般与 await stream.drain() 一起使用
close()
关闭写入器,一般与 await stream.wait_closed()
can_write_eof()
如果支持write_eof 返回True
write_eof()
刷新缓冲的写入数据后,关闭流的写入端
transport
Return the underlying asyncio transport.
返回基础的异步传输
get_extra_info(name, default=None)
drain()
等待,直到适合继续写入流为止
is_closing()
如果流被关闭 或者 正在关闭,返回True
wait_closed()
await stream.wait_closed() 等待流关闭
<4>补充Unix套接字
操作和一般的一样,同样是返回reader和writer,只不过使用的事本机unix套接字
asyncio.open_unix_connection( path = None,***,loop = None,
limit = None,ssl = None,sock = None,server_hostname = None,ssl_handshake_timeout = None)
建立Unix套接字连接并返回一对 。(reader, writer)
与open_connection()Unix套接字类似,但可在Unix套接字上运行。
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套接字服务器。
start_server()与Unix套接字类似,但可以使用。
原文链接:https://blog.csdn.net/sunt2018/article/details/107555021