WebSocket是一种在单个TCP连接上进行全双工通信的协议。它允许服务器主动向客户端发送消息,是实现服务器推送技术的一种方式。WebSocket API已经被大多数现代浏览器支持,包括Internet Explorer 11及以上版本。本文将介绍如何使用PHP编写WebSocket服务器,以及如何使用HTML和JavaScript创建WebSocket客户端。
WebSocket协议定义在RFC 6455中,它通过一个二进制头部包含操作码、长度和掩码信息,后跟数据块。数据的解释和可选的HTTP头部在握手过程中不被定义:
Sec-WebSocket-Protocol
许多简单的WebSocket示例忽略了协议,只是将字符串(可能编码为JSON)发送到服务器,服务器被设计为理解它。但是,如果将这样的客户端连接到另一个WebSocket服务器,几乎可以发生任何事情。
可以定义自己的WebSocket数据解释方法,称之为“协议”,给协议一个名称,比如“myprotocol”,然后让JavaScript以这种方式打开WebSocket连接:
var host = "ws://some.host.or.other/";
var protocol = "myprotocol";
socket = new WebSocket(host, protocol);
服务器然后知道它必须为这个连接使用“myprotocol”。实际上,服务器可以根据协议和/或URL的内容处理不同的数据,因为这一切都取决于开发者。
一个“真正的”WebSocket服务器将与标准Web服务器集成,接受像“http://some.url/”这样的请求并提供HTTP服务,接受像“ws://something”这样的请求并提供WebSocket服务,通常都在端口80上。一个“作弊”的WebSocket服务器只是在给定的端口号上运行并接受套接字连接。
下面是一个用PHP编写的WebSocket服务器示例,可以在命令行上运行它,如果安装了PHP,或者从本地Web服务器上运行它。它乐于接受来自网络上任何地方的连接,只要配置路由器等允许它的监听端口号通过。
它被编写为只接受带有有效协议的连接。如果浏览器中的JavaScript请求:
socket = new WebSocket(host, 'myprotocol');
那么,在连接时查看Chrome开发者工具(Network/Headers)中的头部,会看到:
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,anotherprotocol
允许服务器决定提供哪一个。示例服务器代码有一个处理程序列表,每个协议类型一个:
$protocolHandlers = array(
"echo" => 'doEcho', // 简单地将有效载荷回显给所有客户端
"chat" => 'doChat', // 将"[name] message..."发送给所有其他'chat'客户端
"command" => 'doCommand', // 接受对服务器的命令
);
这些示例协议非常简单,但看看它们的差异 - 这希望展示了服务器端不同协议的有用性 - 如果只是为了将代码和开发与同一核心服务器的不同接口分开,并且能够轻松地与所有客户端交谈。
一个示例客户端,它使用服务器的任何协议连接。它有一个帮助按钮。如果这个按钮放在一个Web服务器上,并且与PHP文件一起,它可以通过加载一个不可见的iframe来启动PHP服务器,或者可以在其他地方的某个套接字上运行PHP服务器,只需填写相关的主机IP:端口信息。PHP服务器尝试通过每20秒发送一个WebSocket ping来保持套接字打开,JavaScript API很乐意回复。
将.zip文件提取到某个目录'wsdemo'中。如果这个目录在有PHP可用的本地Web服务器上,可以直接浏览到http://myserver/wsdemo/websockets2.html - 假设访问myserver允许访问端口12352。
从浏览器中,如果想要页面为启动它,必须设置PHP脚本的位置,通过输入:
php script url: http://myserver/wsdemo/websockets2.php
要在不同的端口上运行:
php script url: http://myserver/wsdemo/websockets2.php?port=9999
或者可以在浏览器窗口中以调试模式打开:
http://myserver/wsdemo/websockets2.php?debug=1&port=9999
如果目录在本地机器上,必须安装PHP,然后可以从命令行运行websockets2.php并打开websockets2.html在浏览器中。
注意websocket2.php需要JSONsvc2.php。在命令行上,可以通过:
prompt> php websockets2.php -d -p9999
在所有情况下,浏览器应用程序需要知道WebSocket服务器的位置,所以填写WebSocket主机。一些例子:
ws://myserver:12352/
ws://localhost:9999/
默认值是坐在桌子上的Web服务器,所以可以尝试简单地浏览到 - 这可能可用,也可能不可用,但值得一试!
认为将看到WebSocket在各种Web应用程序中被使用得越来越多,现在已经与大多数浏览器兼容。然而,当前版本仍然很年轻,一些部分引起了安全问题(比如数据掩码以防止缓存中毒 - 这简直是可悲的),所以毫不怀疑它在不久的将来会发生变化。
甚至可能有标准化的协议最终会与WebSocket一起使用。与此同时,获取代码,运行一个服务器,打开一个浏览器,然后尝试一下!
支持WebSocketv13的浏览器
在编写本文时,以下浏览器已经用此代码进行了测试:
PC: Internet Explorer 11, Chrome 32, Firefox 26.0 和 Android: Chrome 31, Opera 18
"draft-ietf-hybi-thewebsocketprotocol-17" (!)