使用 Sec-Websocket-Protocol
一个使用 Websocket(php/js)上的不同协议的示例服务器和客户端
引言
本文介绍了一个示例 websocket 服务器(碰巧是用 PHP 编写的)、Sec-WebSocket-Protocol 标头的用法以及 HTML/JavaScript 中的示例客户端。实现协议允许单个 websocket 服务器向不同的客户端呈现不同的接口。
背景
Websockets 在浏览器和服务器之间提供了一种连接,允许数据随时双向发送。目前有多种“服务器推送”方法,但 Websockets 有望取代大多数(如果不是全部)这些“变通方法”。
大多数流行的桌面和移动浏览器都对Websockets 标准(根据RFC 6455)具有原生支持,并提供兼容的 JavaScript API——甚至 Internet Explorer(从 IE v11 开始)也支持。
基本的帧协议在 RFC 6455 中有所描述;一个二进制头包含一个操作码、长度和掩码信息,后面跟着一个数据块。该规范并未定义数据如何被解释,也未定义用于启动握手的可选 HTTP 标头的值:Sec-WebSocket-Protocol。
许多简单的 websocket 示例只是忽略协议,而是使用连接将字符串(可能是 JSON 编码的)发送给被设计用来理解它的某个服务器。但是,如果您将这样的客户端连接到另一个 websocket 服务器,则可能会发生任何事情。
因此,您可以定义自己的解释 websocket 数据的方法,称之为协议,给您的协议命名为“myprotocol”,然后让您的 JavaScript 像这样打开一个 websocket 连接:
var host = "ws://some.host.or.other/
var protcol="myprotocol";
socket = new WebSocket(host, protocol);
然后,服务器就知道它必须就此连接与“myprotocol”进行通信。
实际上,服务器可以根据协议和/或 URL 的内容来编写以处理不同的数据,因为这一切都取决于开发人员。
我们这里看的是一个可以处理多种不同协议的单个 websocket 服务器的示例——允许不同的客户端从同一个服务器请求不同格式的数据。
“真实”与“欺骗”的 websocket 服务器
我不确定是否真的有这样的定义,但是……
一个“真实”的 websocket 服务器将与一个标准的 Web 服务器集成,该服务器接受“http://some.url/”之类的请求并提供 HTTP 服务,并接受“ws://something”之类的请求并提供 websocket 服务——所有这些通常都在端口 80 上。
一个“欺骗”的 websocket 服务器只是运行并在指定的端口号上接受套接字连接。下面的示例 PHP 服务器是“欺骗”的,因为它可以在命令行或标准 Web 服务器(端口 80)上执行,然后它自己在不同的端口上接受 websocket 连接。
这里的示例是一个用于开发用途的“欺骗”websocket 服务器。您可能不想在生产环境中使用它
如果您想与此一起使用一个简单的 Web 服务器,您可以尝试Civetweb或Mongoose。
代码做什么?
websocket2.php
websocket2.php 是一个用 PHP 编写的示例 websocket 服务器,如果您安装了 PHP,可以在命令行上运行它,或者从本地 Web 服务器运行它。只要您配置好路由器等允许其监听的端口号,它就可以接受来自网络任何地方的连接。
它是为了只接受具有有效协议的连接而编写的。如果浏览器中的 JavaScript 请求的是:
socket = new WebSocket(host, 'myprotocol');
那么,使用 Chrome 的开发者工具(网络/标头)查看连接时的标头,我们会看到:
Request URL:ws://192.168.0.42:12352/websocket/websocket2.php Request Method:GET Status Code:101 Switching Protocols Request Headers Cache-Control:no-cache Connection:Upgrade Host:tonywilk.no-ip.org:12352 Origin:http://192.168.0.42 Pragma:no-cache Sec-WebSocket-Key:DMF3ByMTLq+cp7AyMN0qUA== Sec-WebSocket-Protocol:myprotocol <-- browser sends 'can I have this protocol' Sec-WebSocket-Version:13 Upgrade:websocket User-Agent: ... Chrome/32.0.1700.102 Safari/537.36 Response Headers Connection:Upgrade Sec-WebSocket-Accept:L6wqtsHk6dzD+kd9NCYT6Wt7OCU= Sec-WebSocket-Protocol:myprotocol <-- server replies ok Upgrade:WebSocket
事实上,客户端可以这样请求多个协议:
Sec-WebSocket-Protocol:myprotocolv1,myprotocolv2,anotherprotcol
允许服务器决定提供哪个协议。
我们的示例服务器代码有一个处理程序列表,每个协议类型都有一个:
$protocolHandlers= array(
"echo" => 'doEcho', // simply echos payload to ALL clients
"chat" => 'doChat', // sends "[name] message..." to all other 'chat' clients
"command" => 'doCommand', // accepts commands to the server
);
include('./JSONsvc2.php'); // JSONsvc: adds protocol handler "JSONsvc"
(包含的 JSONsvc2.php 会动态地将“JSONsvc”添加到此列表中。)
这些示例协议非常简单,但请注意它们之间的区别——这有望证明不同协议在服务器端的有用性——即使只是为了分离代码和开发同一核心服务器的备用接口,并且能够轻松地与所有客户端进行通信。
JSONsvc 协议稍微复杂一些,将在以后的文章中介绍。
(同时,源代码中有很多注释。)
websocket2.html
一个示例客户端,它使用其任何协议连接到服务器。它有一个帮助按钮
如果将其与 PHP 文件一起放在 Web 服务器上,可以通过加载到不可见的 iframe 中来启动 PHP 服务器,或者您可以在其他某个套接字上运行 PHP 服务器,然后仅填写相关的 IP 地址/端口号信息。PHP 服务器会尝试通过每 20 秒发送一个 websocket ping 来保持套接字打开,JavaScript API 会很乐意地回复。
websocket 服务器的默认端口号是 12352。这可以在命令行或 URL 中更改(有关详细信息,请参阅源代码)。
使用代码
将 .zip 文件解压到某个名为“wsdemo”的目录。
如果此目录位于具有 PHP 的本地 Web 服务器上,那么您就可以开始了,只需浏览到 http://myserver/wsdemo/websockets2.html
——假设您对 myserver
的访问允许访问端口 12352。
从浏览器,如果您希望页面为您启动 PHP 脚本,您必须设置 PHP 脚本的位置,方法是输入:
php script url: http://myserver/wsdemo/websockets2.php
以在不同的端口上运行:
php script url: http://myserver/wsdemo/websockets2.php?port=9999
或者,您可以通过打开一个浏览器来在浏览器窗口中运行 PHP 并进行调试:
http://myserver/wsdemo/websockets2.php?debug=1&port=9999
如果该目录位于您的本地计算机上,您将需要安装 PHP,然后您可以在命令行上运行 websockets2.php
并在浏览器中打开 websockets2.html
。
请注意,websocket2.php
需要 JSONsvc2.php
。
在命令行上,您可以通过以下方式更改默认端口(从 12352 开始)并启用调试:
prompt> php websockets2.php -d -p9999
在所有情况下,浏览器应用程序都需要知道 websocket 服务器的位置,因此请填写 Websocket Host。一些示例:
ws://myserver:12352/
ws://:9999/
默认情况下是连接到我桌子上的 Web 服务器,所以您可以尝试简单地浏览到 http://tonywilk.no-ip.org/wsdemo/websocket2.html
——这可能可用,也可能不可用,但值得一试!
最后
我认为,随着现在与大多数浏览器的兼容性,我们将看到 Websockets 在各种 Web 应用程序中得到更广泛的应用。然而,当前版本仍然很年轻,有些部分引起了安全方面的担忧(例如用于防止缓存中毒的数据掩码,坦率地说,这很可笑),所以我相信它很快就会改变。
最终甚至可能存在用于 Websockets 的标准化协议。
在此期间,请获取代码,运行服务器,打开浏览器,然后玩玩吧!
TonyWilk
注释
支持 Websockets v13 的浏览器
撰写本文时,已使用此代码测试了以下浏览器:PC:Internet Explorer 11,Chrome 32,Firefox 26.0;Android:Chrome 31,Opera 18。
在 Windows PC/笔记本电脑、三星 S3/4、亚马逊 Fire 和 Nexus 7 上。
Websocket 标准
《Websocket 标准》定义了“Sec-WebSocket-Version: 13”,如果您看到指向更高版本号的引用,请检查它们是否是指较早的草案。成为“The Websocket Protocol”第 13 版的文档称为:“draft-ietf-hybi-thewebsocketprotocol-17” (!)