Full Stack Python 系列之 4.12 WebSockets

| 分类 Full Stack Python  | 标签 Full Stack Python  翻译  Python 

本系列文章来自 Full Stack Python简体中文翻译项目

翻译网站地址是 fullstackpython.atjiang.com

查看原文请访问 www.fullstackpython.com

第四章 、十二 WebSockets

WebSocket 是一种 标准协议,用于在客户端和服务端之间进行双向数据传输。WebSockets 协议没有运行在 HTTP 之上,它是基于 TCP 的一种独立实现。

为什么要用 WebSockets?

一个 WebSocket 连接允许在客户端和服务端之间进行全双工通讯,从而每一端都可以通过建立的连接向另一端推送数据。 WebSocket,以及与其相关的 服务端发送事件 (SSE) 及 WebRTC 数据通路 等技术之所以重要的原因是:HTTP不能打开并一直保持连接,不能在服务端和 Web 浏览器之间进行频繁的数据推送。在这之前,大多数的 Web 应用会通过频繁的异步 JavaScript 和 XML (AJAX) 请求来实现长轮循,如下图所示。

通过 AJAX 的长轮循对于一些应用来说相当的低效。

服务端推送相比长轮循效率更高且更具扩展性,因为 Web 浏览器不再需要通过一系列的 AJAX 请求来持续地获取更新。

对于获取服务端所发送的更新来说,WebSocket 比 长轮循理有效率。

虽然上图中所示的是服务端将数据推送给客户端,但是 WebSocket 是一个全双工的连接,因此客户端也能将数据推送给服务端,如下图所示。

WebSocket 也允许客户端向服务端推送数据。

用 WebSockets 来获取服务端/客户端推送的更新,这种方式适合特定类型的 Web 应用,例如聊天室,这也是它之所以经常被用作 WebSocket 库的示例应用的原因。

实现 WebSocket

Web 浏览器和服务端都必须要实现 WebSocket 协议,以便建立和维护连接。因为 WebSocket 的连接是持续连通的,不像经典的 HTTP 连接,因此服务器需要做更多工作。

基于多线程或多进程的服务器不能很好地提供 WebSockets 服务,因为它们的设计是:打开一个连接,尽快处理完请求,然后关闭连接。因此,采用 Tornado 或 打包了 geventGreen Unicorn 等异步服务器,对于实现一个实用的服务端 WebSockets 都是必要的。

而在客户端,使用 WebSocket 并不要求有某个 JavaScript 库。实现了 WebSocket 的 Web 浏览器都会通过 WebSockets 对象 导出所有必要的客户端功能。

但是,JavaScript 封装库实现了优雅地降级(不支持 WebSocket 的情况下通常会采用长轮循机制),并隐藏了不同浏览器间的羞异,使用这些封闭库,会使开发者工作起来更加轻松。 有关 JavaScript 客户端库及 Python 实现的示例在下面列出。

JavaScript 客户端库

  • Socket.io 的客户端 JavaScript 库能与实现了 WebSocket 的服务端进行连接。

  • web-socket-js 是一个基于 Flash 的客户端 WebSocket 实现。

Python 实现

  • Autobahn 使用 Twisted 或 asyncio 来实现 WebSocket 协议。

  • Crossbar.io 构建于 Autobahn 之上,并且包含一个独立的服务器, 如果 Web 应用开发者需要的话,可以用它来对 WebSocket 连接进行单独处理。

Nginx WebSocket 代理

Nginx 从 第 1.3 版 开始就正式支持 WebSocket 代理了,通过配置 Upgrade 和 Connection 头可以确保请求通过 Nginx 并到达你的 WSGI 服务器。第一次设置可能会有一点难度。

下面是我的 WebSockets 代理的 Nginx 配置。

# this is where my WSGI server sits answering only on localhost
# usually this is Gunicorn monkey patched with gevent
upstream app_server_wsgiapp {
  server localhost:5000 fail_timeout=0;
}

server {

  # typical web server configuration goes here

  # this section is specific to the WebSockets proxying
  location /socket.io {
    proxy_pass http://app_server_wsgiapp/socket.io;
    proxy_redirect off;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 600;
  }
}

值得注意的是,如何上面的示例配置不能工作,你应该查看 官方的 HTTP 代理模块文档

下面的这些资源对于正确的配置也很有帮助。

使用 WebSockets 的开源 Python 示例

python-websockets-example 包含了创建一个简单 Web 应用的代码,它使用 Flash、Flask-SocketIO 和 gevent 来提供 WebSockets。

  • Flask-SocketIO 项目中有一个 聊天室 Web 应用,演示了如何发送服务端生成的事件,以及如何通过表单的文本输入框来获取用户输入。

通用 WebSocket 资源

  • 官方的 W3C WebSockets API 候选草案WebSockets 工作草案 都是不错的参考材料,但是对于刚接触 WebSockets 概念的开发者来说会有点难度。我建议先看下面列出的一些对初学者来说较容易的资料,然后再读那份工作草案。

  • 由 Armin Ronacher 写的 WebSockets 101 提供了一份有关 HTTP 代理对 WebSockets 低水平支持的详细评估报告。同时对 WebSockets 协议的复杂性及其实现也进行了探讨。

  • “我能使用吗?” 网站上有一份 非常有用的 WebSockets 参照表,指出了哪些浏览器及其版本支持 WebSockets。

  • Mozilla 的 WebSockets 开发者资源 是一个查找 WebSockets 开发相关文档与工具的好地方。

  • 从零开始学 WebSockets 先对该协议进行了概述,然后对 WebSockets 的低层知识进行了讲解,这些知识对于只使用 Socket.IO 等库的开发人员来说通常是个黑盒子。

  • websocketd 是一个 WebSockets 服务程序,意在成为 “WebSockets 的 CGI”。值得一看。

Python 相关的 WebSockets 资源


上一篇     下一篇