编写 WebSocket 服务器

WebSocket 服务器是一个 TCP 应用程序,监听服务器上任何遵循特定协议的端口,就这么简单。创建自定义服务器的任务往往听起来很吓人,然而,在你选择的平台上实现一个简单的 WebSocket 服务器是很容易的。

WebSocket 服务器可以用任何实现了 Berkeley sockets 的服务器端编程语言编写,如 C(++) 或 Python 甚至 PHP 服务器端 JavaScript 。这不是任何特定语言的教程,而是作为指导,以方便编写自己的服务器。

你需要知道 HTTP 的工作原理,并具有中级编程经验。根据语言帮助(Depending on language support),可能需要 TCP 套接字的知识。本指南的范围是介绍编写 WebSocket 服务器所需的最低知识。

备注: 阅读最新的官方 WebSockets 规范, RFC 6455 . 第 1 节和第 4-7 节对服务器实现者特别有意思。第 10 节讨论安全性,你应该在暴露你的服务器之前仔细阅读它。

WebSocket 服务器在这里被解释得非常底层。WebSocket 服务器通常是独立的专用服务器(出于负载平衡或其他实际原因),因此你通常会使用 反向代理 (例如常规 HTTP 服务器)来检测 WebSocket 握手,预处理这些握手,并将这些客户端发送给 一个真正的 WebSocket 服务器。(例如)这意味着你不必使用 cookie 和身份验证处理程序来扩充服务器代码。

WebSocket 握手

首先,服务器必须使用标准的 TCP 套接字来监听传入的套接字连接。根据你的平台,这可能已经为你处理。例如,假设你的服务器正在监听 example.com,端口 8000,并且你的套接字服务器响应 /chat 上的 GET 请求。 .

警告: 服务器可以监听它选择的任何端口,但是如果它选择了 80 或 443 以外的端口,防火墙和/或代理服务器可能会有问题。端口 443 上的连接往往会更容易成功,但是当然,这需要一个安全的连接(TLS / SSL)。另外请注意,大多数浏览器(特别是 Firefox 8+)不允许从安全页面连接到不安全的 WebSocket 服务器。

握手是 WebSockets 中的“Web”。这是从 HTTP 到 WS 的桥梁。在握手过程中,有关连接的详细信息正在初始化中,如果条件不利,任何一方可以在完成之前退出。服务器必须小心了解客户要求的一切,否则会产生安全问题。

客户端握手请求

即使你正在构建服务器,客户端仍然必须启动 WebSocket 握手过程。所以你必须知道如何解释客户的请求。客户端将发送一个相当标准的 HTTP 请求,看起来像这样(HTTP 版本必须是 1.1 或更高,方法必须是 GET ):

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

客户可以在这里请求扩展和/或子协议;详情请见杂项。当然,你也可以在这里加上你所需要的一般请求头如User-AgentRefererCookie或者认证头。WebSocket 没有作要求,忽略它们也是安全的。在大多数情况下,反向代理已经做了这些处理。

如果任何请求头信息不被理解或者具有不正确的值,则服务器应该发送“400 Bad Request”并立即关闭套接字。像往常一样,它也可能会给出 HTTP 响应正文中握手失败的原因,但可能永远不会显示消息(浏览器不显示它)。如果服务器不理解该版本的 WebSocket,则应该发送一个Sec-WebSocket-Version头,其中包含它理解的版本。(本指南解释了最新的 v13)。下面我们来看看奇妙的请求头Sec-WebSocket-Key

备注: 所有浏览器将会发送一个 Origin请求头。你可以将这个请求头用于安全方面(检查是否是同一个域,白名单/ 黑名单等),如果你不喜欢这个请求发起源,你可以发送一个403 Forbidden。需要注意的是非浏览器只能发送一个模拟的 Origin。大多数应用会拒绝不含这个请求头的请求.。

备注: 请求 URI(这里的是/chat)在规范里没有定义。很多开发者聪明地把这点用于控制多功能 WebSocket 应用。例如example.com/chat会请求一个多方会话应用,而在相同服务器上example.com/game则会请求一个多玩家游戏应用。

备注: 常规 HTTP 状态码只能在握手之前使用。握手成功后,你必须使用一组不同的代码(在规范的第 7.4 节中定义)。