WebSocket服务器与客户端实现

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服务器与“作弊”WebSocket服务器

一个“真正的”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" (!)
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485