前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >虚拟茶话会(2):再次实现

虚拟茶话会(2):再次实现

作者头像
不可言诉的深渊
发布2019-07-26 16:33:19
7840
发布2019-07-26 16:33:19
举报

虚拟茶话会(1):初次实现

第一个原型虽然是个管用的聊天服务器,但其功能很有限,最明显的缺陷是没法知道每句话都是谁说的。另外,它也不能解释命令(如say或logout),而最初的规范要求提供这样的功能。有鉴于此,需要添加对身份(每个用户都有唯一的名字)和命令解释的支持,同时必须让每个会话的行为都依赖于其所处的状态(刚连接、已登录等)。添加这些功能时,必须确保程序是易于扩展的。

5.1.基本的命令解释功能

我将演示如何模仿标准库模块cmd中Cmd类的命令解释功能。(遗憾的是,你不能直接使用这个类,因为它只能用于处理sys.stdin和sys.stdout,而你处理的是多个流)你需要一个函数或方法,用于处理用户输入的单行文本。这个方法应提取第一个单词(命令),并根据这个单词调用相应的方法。例如,如果文本行像下面这样:

say Hello,world!

将导致这个函数调用下面的方法:

do_say('Hello,world!')

do_say还可能将会话本身作为参数,以便知道是谁在说话。

下面是一种简单的实现,其中还包含一个处理未知命令的方法。

在这个类中,使用了getattr。实现基本的命令处理功能后,需要定义一些命令,并根据会话当前的状态决定哪些命令可用(以及它们将做什么)。如何表示会话的状态呢?

5.2.聊天室

每种状态都可用一个自定义的命令处理程序表示,很容易将此与标准的聊天室表示法(MUD中的地点)结合起来使用。每个聊天时都是一个包含特定命令的CommandHandler。另外,它还应记录聊天室内当前有哪些用户(会话)。下面是一个通用的超类,所有聊天室都将继承它。

除基本方法add和remove外,它还包含方法broadcast,这个方法对聊天室内的所有用户(会话)调用push。这个类还以方法do_logout的方式定义了一个命令——logout。这个方法引发异常EndSession,而这种异常将在较高的层级(found_terminator中)处理。

5.3.登陆和退出聊天室

除表示常规聊天室(这个项目中只有一个这样的聊天室)之外,Room的子类还可表示其他状态,这正是你创建Room类的意图所在。例如,用户刚连接到服务器时,将进入专用的LoginRoom(其中没有其它用户)。LoginRoom在用户进入时打印一条欢迎消息(这是在方法add中实现的)。他还重写了方法unknown,使其让用户登录。这个类只支持一个命令,即命令login,这个命令检查用户名是否是可接受的(不是空字符串,且未被其它用户使用)。

LogoutRoom要简单得多,它唯一的职责是将用户的名字从服务器中删除(服务器包含存储会话的字典users)。如果用户名不存在(因为用户从未登录),将忽略因此而引发的KeyError异常。


注意 虽然服务器中的字典users存储了指向所有会话的引用,但根本没有从中获取会话。字典users只用于记录哪些用户名被占用。然而,我没有将用户名关联到随便选择的值(如True),而是将其关联到相应的会话。虽然现在这样做没什么用处,但在以后的程序版本中可能发挥作用(例如,让用户能够发私信时)。也可采用另一种做法,将会话存储在一个集合或列表中。


5.4.主聊天室

主聊天室也重写了方法add和remove。在方法add中,它广播一条消息,指出有用户进入,同时将用户的名字添加到服务器中的字典users中。方法remove广播一条消息,指出有用户离开。

除这些方法外,ChatRoom类(主聊天室)还实现了三个命令。

  • 命令say(由方法do_say实现)广播一行内容,并在开头指出这行内容是哪位用户说的。
  • 命令look(由方法do_look实现)告诉用户聊天室内当前有哪些用户。
  • 命令who(由方法do_who实现)告诉用户当前有哪些用户登录了。在这个简单的服务器中,命令look和who的作用相同,但如果你对其进行扩展,使其包含多个聊天室,这两个命令的作用将有所区别。

5.5.新的服务器

至此已介绍了大部分功能。对于ChatSession和ChatServer类,所做的主要改进如下。

  • ChatSession新增了方法enter,用于进入新的聊天室。
  • ChatSession的构造函数使用了LoginRoom。
  • 方法handle_close使用了LogoutRoom。
  • ChatServer的构造函数新增了字典属性users和ChatRoom属性main_room。

另外请注意,handle_accept不再将新的ChatSession添加到会话列表中,因为现在会话由聊天室管理。


注意 一般而言,如果你实例化一个对象(就像handle_accept中的ChatSession),而不将其赋给变量或添加到容器中,它将丢失并可能当作垃圾收集(这意味着它将完全消失)。由于所有的dispatcher都由asyncore处理(引用),而async_chat是一个dispatcher子类,因此在这里不是问题。


聊天服务器的最终代码如图所示。

聊天服务器支持的命令

下图是一个聊天过程示例。在这个示例中,服务器是使用如下命令启动的:

python chatserver.py

而用户win10是使用如下命令连接到服务器的:

telnet localhost 5005

6.进一步探索

对于这个基本服务器,可以在很多方面进行扩展和改进。

  • 你可以创建包含多个聊天室的版本,还可按自己的想法扩展命令集。
  • 你可能想让这个程序只能识别某些命令(如login或logout),并将其他文本都视为聊天内容,这样就不需要命令say了。
  • 你可在所有命令前加上特殊字符(如斜杠,让命令类似于/login或/logout),并将不以特殊字符打头的内容都视为聊天内容。
  • 你可能想创建自己的GUI客户端,但这比想象的要难些。GUI工具包提供了一个事件循环,而要与服务器通信,可能还需要一个事件循环。为让这些事件循环相互协作,你可能需要使用线程化。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python机器学习算法说书人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档