12月13, 2019

Python 做 UI 超 easy(6.1)——实现自己的网络服务

上一节我们使用了第三方天气预报接口,配合自己做的视窗界面,实现了一个相当不错的天气预报程序。现在回顾一下,天气预报小程序是怎样工作的。

TIPS:
时不时盘点一下成果,可以避免写代码真的成为 "搬砖"。
很多人对编程存在误解,以为编程就是噼里啪啦敲键盘。其实编程更像是写文章,写字本身不是重点(当然不会写也不行),头脑中的思想才是!
写代码的过程,只不过是实现头脑中的构思。每一个软件都是一个小型系统,通过复盘深入理解所有细枝末节,管理好有限的资源才是核心技能。
互联网时代,很多优秀的开发者,本身也是先进的管理者,也很容易理解了。

互联网的奇迹

现在很少有不联网的电脑,没有网络,计算机的价值要大打折扣。我们的天气预报小程序虽然很简单,但是不折不扣的互联网应用

title

前面已经提到,本机运行的天气预报程序是客户端。无论多复杂的客户端,大体只负责两件事:

  • 接受客户输入;
  • 展示服务端的数据。

用户虽然可以利用天气预报程序得知天气预报,但是真正的天气数据收集、预测、发布工作,都是在服务端完成的,客户端只是展示而已。这种模式相比较以往所谓 “单机” 程序有深远的意义:

  • 业务可以做的更大更复杂,但是却更廉价。现在的服务基本都在 “云” 上,国内常见的阿里云,国外有世界知名的亚马逊云服务。服务端拥有更好的硬件资源,提供更强大的性能,却对客户端机器没什么太多要求;服务端同时为很多人服务,对于客户来说,成本反而降低了,服务端数据相当于薄利多销。
  • 极大保护知识产权。Python 程序属于脚本语言,我们的天气预报程序几乎无法对抗用户对它进行修改。由于真正的服务在服务端,天气数据也在服务端,用户对客户端的修改,对天气预报业务的损失非常小。如果有账号系统,极端情况下,我们让搞破坏的用户下线就好了。
  • 软件运维方便。由于天气预报业务在服务端完成,如果我们采用了新的 “天气模型”,只要 “偷偷” 在服务端修改就好了,用户几乎察觉不到什么变化。特别是服务端程序故障端时候,可以直接登陆到自己到服务器上修复。在互联网兴起之前,一旦程序出现问题,就只能期待着用户会更新安装包。

TIPS
强烈推荐 《黑客与画家》—— Paul Graham,作者对软件工程、技术人员职业生涯有很不错的见解。

当然了,天气预报程序的天气预报服务不是我们做的,但是必须承认,它才是天气预报业务的核心。

在之前的项目中,我们利用 requests 库发起 HTTP 请求,从天气预报 web 接口获得天气预报数据。如果你还有印象的话,天气预报的数据是 Json 格式,一种非常像 Python 字典的数据格式。

title

服务端是如何提供服务端呢?大体步骤就 2 个:

  • 接受请求
  • 返回数据

再接受请求和返回数据之间,是服务端辛勤工作的时机,以便准备有用的信息给客户端 “返回”。

一图胜千言,仔细看一下客户端与服务端之间的交互过程。

TIPS
客户端与服务端的通信通常是基于请求——响应模式,称之为交互。

title

服务端的业务就发生在黄色部分,通常是一些访问数据库、数据整理的工作。

定睛一看服务端

客户端主要是获取数据,展示,非常简单,而且之前编写天气预报视窗程序的工作,都属于在客户端的努力。

我们在客户端已经投入了相当的精力,现在不妨仔细看看一下服务端是如何工作的,虽然不一定每个人都有必须自己写服务端,我的建议还是:知其所以然!

  1. 客户端如何找到服务端的机器?
    互联网与电话网有很多相似性(实际上早期很多人用过电话拨号上网,互联网可以运行在电话网络上)。

首先看一下你家里的座机。

网络中的电话机千千万,电话是通过编号区别的。在互联网中,这个编号叫 IP 地址(IP address),通常简称 IP。

title

假设你家的电话号是 883454,这个号码是由运营商分配给你的。这个号码全市唯一,别人就不能再用这个号了。这样,所有人都可以用这个号码找到你(外市可能要加区号,暂时搁置这个问题好嘛)。在互联网中这样的号码叫 “公网地址”,是全球唯一的。

同时你家里有很多分机,它们需要一个你家里的唯一分机号,比如 01,02 等等。互联网中也有类似的情况,比如同一 Wifi 下的所有设备都会得到一个当前 Wifi 下的唯一 “分机号”,称之为 “局域网地址”。相对于公网,局域网也称为 “内网” 或者 “私网”。

注意,局域网地址只要保证在 “局部” 唯一就可以,比如你家的某个分机号为 01,别人家也可能会在自己家用分机号 01,互不干扰,各家是各家的事。“局域网” 的 “局域” 俩字儿就是这个意思,分机号只能保证在局部唯一。

因此:

  • 同一内网所有 “分机“ 之间可以用局域网地址互相通信,
  • 任意内网 ”分机“ 也可以向任意公网 IP 通信,
  • 内网 ”分机“ 无法直接与其他局域网中的分机通信。

title

该说服务端了,服务端也是一样,也拥有自己的公网地址,而且它的内部也会有很多分机,拥有自己的局域网地址。比如上图展示的客服公司,拥有自己的电话号(公网地址) 和内网的一些分机。

TIPS
直接将计算机暴露在公网地址是很危险的行为,因为互联网实际上是对等的,任何拥有公网地址的计算机都可以接收、发送数据,换句话说任何公网下的计算机可以同时扮演 “客户端” 和 “服务端”。一旦你的计算机可以任由其他人连接,没有足够专业知识的情况下,很有可能被不怀好意的人攻击,造成损失。
好在大多数情况下,个人计算机得到的只是运营商自建局域网的 “分机号”,运营商只允许内部局域网的计算机作为客户端,极大的降低了个人计算机被主动攻击的可能行。倒也不是运营商热心,主要是服务器地址(公网地址)有经济价值,所以阉割掉了普通用户计算机对全球提供服务的能力。
如果希望局域网计算机对公网提供服务,可以了解 “内网穿透” 技术。

服务端会处理很多业务,就像一家公司可能有商务部、销售部、技术部。我们可以通过电话找到一家公司,还需要额外的信息指定要联系的具体业务部门,一种方式是公司为不同业务开不同的窗口,并编号。这样只需要通过 电话 + 窗口编号,就可以直接展开业务洽谈。

服务端采用类似的策略,不过这种窗口称为端口,以整数编号。比如天气预报的 HTTP 服务,使用的是 80 端口,客户端通过:

  • 公网地址:端口号

直接找到天气预报数据服务。最终具体干活的是服务端内部的某个 “分机”,这样的细节对客户端就没什么意义了。

  1. 天气接口的组成

IP 是一组二进制数据,通常为了方便,将他们以 "." 分割为 4 个 0~255 的整数,比如百度的一个 IP 地址是:220.181.38.150。 百度的服务也是 HTTP 服务,我们就可以在浏览器中填写 220.181.38.150:80 访问百度主页。

不对啊,我记得天气预报的接口是:http://wthrcdn.etouch.cn/weather_mini,没有 IP 和 端口啊!

其实是有的,我们对天气预报接口进行分解,得到: title

  • 协议,确定数据组织格式。
  • 域名,其实是为了解决 IP 地址难记的问题,baidu.com 就比 220.181.38.150 好记的多。有专门的服务(DNS)会自动将域名转换为 IP 地址。所以天气预报接口是有 IP 地址的,不过是隐含的。
  • URL,定位了资源在服务上的位置,很像计算机上的分级目录。
  • 端口,由于 80 端口是 HTTP 协议的默认端口,所以在接口中没有指明。你也可以用 wthrcdn.etouch.cn:80 替代 wthrcdn.etouch.cn,不会有任何影响。

再总结一下,服务端所需要的东西:

  • 使用 HTTP 协议;
  • 服务端有一个 IP,
  • 指定一个端口,默认 80 端口;
  • 就收请求,请求中包含 URL 信息,
  • 准备一些数据

最终返回给客户端。

TIPS
一个特殊的地址:localhost 或者 127.0.0.1,是本机的 IP 地址。本机可以通过这个地址,自己与自己通信。

自己动手,丰衣足食

说了这么多,其实我就是想自己做一个服务端。

TIPS
用 Python 编程,一定要站在巨人的肩膀上。

今天的巨人是第三方库 bottle。这是一个非常轻量级的 web 框架,可以用来构建 http 服务。在这里查看它的文档。

从上一节开始,我们不再使用 online 环境,开始使用本地开发环境,毕竟本地方便的多。

首先在命令行安装 bottle:

pip install bottle

废话不多说,新建一个 bottle_demo 目录,在其中创建 main.py:

from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

run(host='localhost', port=8080)

快速运行第一个 web 程序

注意 run(host='localhost', port=8080),指定的就是 web 服务的 IP 地址和端口,localhost 表示在本机服务,port 的值是 8080,也就是这个小 web 服务在本机的 8080 端口工作。示意图如下:

title

然后打开浏览器,在地址栏输入:http://localhost:8080/hello/Jiangchuan,也可以用你的名字替换 Jiangchuan,就会看到第一个 web 服务运行起来了。

title

下面再仔细看一下地址栏中的信息与代码之间的关系。

title

由于代码中指定的端口是 8080,没有使用 HTTP 协议默认的 80 端口,所以在地址栏必须填写端口,不能省略。

如果希望改变 URL,就需要修改上图对应位置的代码,你可以试一试。

总结

复盘一下天气预报程序,服务端竟然才是核心,写了这么多,离实现天气预报服务还有很多事要做。

不过已经了解了 IP、域名、URL 之类的东西了,至少也运行起第一个 HTTP 服务实现 Say hi,也值得自己鼓励自己一下!

你要是问我,不是搞 PySimpleGUI 吗,搞什么 HTTP 服务呢?很快你会明白我的用心的。

明天继续咯。

本文链接:http://www.thinkinpython.com/post/PySimpleGUI_6_1.html

-- EOF --