• 流畅python学习笔记第十八章:使用asyncio编写服务器


    在这一章中,将使用asyncio写一个TCP服务器。这个服务器的作用是通过规范名称查找Unicode字符,来看下代码:

    import asyncio

    from charfinder import UnicodeNameIndex

     

    CRLF=b' '

    PROMPT=b'?>'

    index=UnicodeNameIndex()

    @asyncio.coroutine

    def handle_queries(reader,writer):

        while True:

            writer.write(PROMPT)

            yield from writer.drain()

            data=yield from reader.readline()

            try:

                query=data.decode().strip()

            except UnicodeDecodeError:

                query='x00'

            client=writer.get_extra_info('peername')

            print('Received from {}:{!r}'.format(client,query))

            if query:

                if ord(query[:1])<32:

                    break

                lines=list(index.find_description_strs(query))

                if lines:

                    writer.writelines(line.encode()+CRLF for line in lines)

                writer.write(index.status(query,len(lines)).encode()+CRLF)

                yield from writer.drain()

                print('Sent {} results'.format(len(lines)))

        print('Close the client socket')

        writer.close()

     

    def main(address='127.0.0.1',port=2323):

        port=int(port)

        loop=asyncio.get_event_loop()

        server_coro=asyncio.start_server(handle_queries,address,port,loop=loop)

        server=loop.run_until_complete(server_coro)

        hosts=server.sockets[0].getsockname()

        print('Serving on {}. Hit CTRL_C to stop'.format(hosts))

        try:

            loop.run_forever()

        except KeyboardInterrupt:

            pass

        print('Server shutting down')

        server.close()

        loop.run_until_complete(server.wait_closed())

        loop.close()

     

    if __name__=="__main__":

    main()

    main函数的运行过程如下:

    (1)在main中默认两个参数:addressport

    (2)asyncio.start_server的协程运行完后,返回的协程对象返回一个asyncio.Server实例,这个实例是一个TCP套接字服务器,封装了诸如socket函数,并且会给handle_queries传递StreamWriter.writeStreamReader.readline进行读写操作。

    (3)server=loop.run_until_complete(server_coro)驱动协程,启动服务器

    (4)获取这个服务器的第一个套接字的地址和端口

    (5)loop.run_forever() 运行事件循环,main在这里被阻塞,直到服务器的控制台中按下CTRL-C键才会关闭

    (6)最后关闭服务器,终止事件循环

    来看下handle_queries的操作过程:

    (1)函数接收2个参数,readerwriter,在asyncio.start_server中传递进来

    (2)writer.write(PROMPT),这个其实是StreamWriter.write, 这个方法不是协程因此不能采用yield from。这个是给终端界面输出?>

    (3) writer.drain刷新writer缓冲,因为它是协程,因此采用yield from

    (4)yield from reader.readline()是从缓冲区读取字符,这个方法是一个协程,返回一个bytes对象

    (5)writer_get_extra_info返回的是与套接字连接的远程地址

    (6) 下面是输出查询到的字符到终端并在每行末尾添加了回车符和换行符

    writer.writelines(line.encode()+CRLF for line in lines)

                writer.write(index.status(query,len(lines)).encode()+CRLF)

    (7)关闭StreamWriter

    代码运行效果如下,当输入chess black的时候会返回查询到的结果

    从服务器代码中可以看到打印的如下信息

    /usr/bin/python3.6 /home/zhf/py_prj/function_test/asy_server_try.py

    Serving on ('127.0.0.1', 2323). Hit CTRL_C to stop

    Received from ('127.0.0.1', 46670):'chess black'

    Sent 6 results

  • 相关阅读:
    设计模式:单一职责原则
    多线程的创建
    Android开发基础(java)14
    面向对象编程的思想(6)
    面向对象编程的思想(5)未完成
    面向对象编程的思想(4)
    面向对象编程的思想(3)
    面向对象编程的思想(2)
    面向对象编程的思想(1)
    GDB 命令详细解释
  • 原文地址:https://www.cnblogs.com/zhanghongfeng/p/8674789.html
Copyright © 2020-2023  润新知