6.11 一个图形使用画布的WebSockets聊天应用
在下面的例子中我们将看到一个更实用的画布应用程序:一个伪3D聊天应用程序(如图6-15所示)。这个例子将演示如何将画布和其他HTML5特性如WebSockets结合。
6.11.1 WebSockets优势
除画布外,另一个同样令人振奋(但可能比较不知名)的HTML5元素是WebSockets。虽然这本书是关于图形的,但还是值得讨论一下为什么WebSockets对现代Web应用程序意义重大,以及如何将它们与画布集成。
通常服务器和客户端浏览器之间是用HTTP协议传递数据的,但HTTP有一定的局限性(和新的WebSockets相比),使它不适合高速、双向的网络通信。
HTTP是单行线
HTTP的模式是:客户端Web浏览器向服务器请求数据,服务器满足其要求。服务器不能在没有被请求的情况下“推送”信息到客户端。
它的开销很大
HTTP数据携带了大量的头信息。请求一个字节的数据可能会导致发送数百个字节的、额外的、“看不见的”头信息也被发送。头信息通常包含被传送数据的性质,如内容类型、缓存、编码等。
它的连接都是非持久的
为每个HTTP请求,都必须重新建立连接,发送数据,再关闭连接。这好比是电话交谈时每说完一句话就得重新拨号。
你可以使用Comet/长轮询等编程技术,模拟持久、双向的连接,从而提高HTTP的性能。虽然这些技术可以提供一些改善,但有可能服务器无法支持这些技术所需要的超高HTTP连接数;如Apache这样的服务器在处理此类连接时就不是特别有效率。最终你会发现:对多人游戏和其他快速通信的应用程序而言,HTTP的网络传输效率太低,即使用前面的技术还是无力回天。
WebSockets通过真正持久和双向的连接来解决这些问题。客户端可以在任何时候给服务器发送数据,反之亦然。此外,数据开销非常小,因为一旦建立了连接就不需要传递头数据。只是在数据前后各加了一个0字节(0x00)和0xFF表示结束和终止。
6.11.2 WebSockets支持和安全
目前有Firefox 4+、Google Chrome 4+、Opera 10.70+和Safari5支持WebSockets。不过由于WebSockets通信相关的安全问题,使得Firefox和Opera的开发者关闭了默认的WebSockets功能,而其他浏览器厂商可能也会采取同样的行动。
在解决安全问题之前,默认WebSockets功能看来还处于不太稳定的状态。然而,我们可以现在就试验WebSockets协议,为未来做好准备。
在Firefox 4和Opera 11上的WebSockets
幸运的是,Firefox和Opera用户可以在开发中打开WebSockets功能。
Firefox4:
1.在浏览器的地址栏输入about:config。
2.查找和更改network.websocket.override-security-block标志。
Opera:
1.在浏览器的地址栏输入opera:config。
2.在首选项编辑器,打开“用户首选项”部分,并设置Enable WebSockets。
6.11.3 聊天应用程序
我们的聊天应用程序大致由4个主要部分组成:
- 在Web服务器上运行的套接字服务器;
- 可以左右移动和“聊天”的客户化身(avatar);
- 聊天文字;
- 文本输入区。
当用户连接到聊天页面时,将自动为他创建一个颜色随机的化身。然后用户可以在页面上点击来移动化身,也可以在聊天框中输入文字。化身的移动和聊天文字将反映给所有其他的连接用户。也就是说,每个用户看到的都是相同的页面,但只能控制自己的化身。
1.套接字服务器
套接字服务器需要处理连接,并在连接的客户端之间传输信息。它必须运行在所有客户端可以连接到的服务器上。
套接字服务器的编程语言可以是任何流行的服务器端语言,如PHP、Java或Python。JavaScript程序员可以关注node.js,它是一个基于服务器的JavaScript实现和使其适合高效网络编程的一些相关库。
这个例子里我选择了PHP,因为几乎所有基于Linux的托管主机上都已安装了PHP。
提示:
套接字服务器(server.php)实际上由两部分组成:一个通用的套接字处理类(WebSocketServer),可用于各种应用;一个聊天应用程序特定的回调函数(process()),这是为我们的聊天应用程序定制的。请从本书的代码中阅读server.php的源代码。
本书不可能展开讨论PHP。PHP语言比较简单易学,网上有大量的学习资源。如果你打算仔细看看套接字服务器代码,请注意下面几个PHP语法:
- 变量前面有一个美元符号(不要和jQuery中的$混淆)。
- 字符串连接符号不是加号(+),而是句号(.)。这点比较特殊。
套接字服务器至少要执行以下操作:
- 接受新连接,并保持连接的客户端列表;
- 接收来自客户端的数据更新(聊天的文字和位置);
- 传输数据更新到所有连接的客户端;
- 当连接断开时(如浏览器关闭),从列表中删除客户。
2.在本地安装一个网站托管环境
除非你有专门或虚拟主机的root权限,否则是不可能让套接字服务器工作的。正确配置的共享网站托管环境都会有一个防火墙,防止使用任何的通信端口。幸运的是,你可以安装一个本地环境来运行服务器端代码。
安装一个网站托管环境曾经是痛苦而漫长的过程。幸好“Apache Friends”XAMPP软件将所需模块(Apache和PHP)合并到一个下载文件中,你可以在几分钟之内将其安装到Windows、Mac或Linux系统上。
图6-16显示了XAMPP的控制面板。注意PHP是以透明方式运行的,在控制面板中不显示。
要通过XAMPP启动套接字服务器,单击XAMPP控制面板上的Shell按钮。这将呈现一个命令行,使你可以运行套接字服务器(如图6-17所示)。输入php path-to-socket-server\server.php来运行套接字服务器,然后按Enter键。
你需要将server.php的路径改为这个文件在你本地机器上的位置。
套接字服务器现在正在等待聊天应用JavaScript端的连接。
最后,我们需要在浏览器中运行实际的聊天网页(JavaScript)。
当我们使用file:///协议时,我们从浏览器直接访问HTML文件,并没有用到Apache。
你还可以打开多个浏览器来测试多个聊天网页的实例,自己和自己聊天。
测试聊天应用程序更精细的一个方式是通过网络(Web服务器)来运行聊天服务器、提供聊天页面。这里涉及的步骤有:
(1)在Web服务器上,修改Apache的httpd.conf文件中的一个虚拟主机条目,将Web服务器的IP地址映射到Web服务器上聊天应用程序的位置。定义的第一个虚拟主机是Web服务器IP地址的默认主机。
(2)通过XAMPP控制面板启动Apache。
网络上其他计算机的用户可以通过在合适的浏览器上输入Web服务器的IP地址,连接到聊天应用程序。
3.相机
相机对象决定了聊天区域的透视图。它包含了3个应用函数:
setFOVandYPos()
传入相机的视野(FOV, Field of View)的角度和垂直位置。从视野计算相机距离使你可以改变画布大小,而不影响呈现的视图(假设高宽比不变)。我们使用125度的视野和−128的相机y位置。
worldToScreen()
从传入的世界坐标计算画布屏幕上的坐标。它给化身计算尺度使得它们在远处显得比较小,有效地模拟透视效果。
screenToWorld()
这个函数和 worldToScreen()相反,从画布上的位置得到对应的世界坐标。screenToWorld()将鼠标单击的位置转化为用户化身的新世界坐标位置。我们使用toFixed()方法防止返回值过于精细。例如,188.42620390960207将被188.426替代,因为前者需要更长的网络传输时间且没有太多必要。
4.化身
化身是客户端的图形表示。它们各自以随机颜色出现,以区别于其他化身。我们通过单击鼠标将其移动要新位置上。它们由分别代表头和身体的两个矢量形状组成。我们对化身用径向渐变填充以增加其深度效果,使用深色描边来将其和背景分离。
5.聊天文字
聊天的文字将在“发言的”化身上方出现,并随着用户输入更多文字逐渐向屏幕上方移动。为了使文字更清晰并加入聊天泡泡的效果,我们用白色填充的圆角矩形环绕文字,并用化身的颜色给这个矩形描边。
当化身聊天时,textScroller对象管理和绘制生成的文字。addText()方法将新的文字添加到列表的开始,同时删除5句之前的文字。这创建了垂直的滚动效果,文字向画布上方移动时最顶层的文字将丢失。这个方法接受化身的水平位置作为文字的中心位置,以及化身的颜色。
drawText()方法遍历文字列表,并绘制每一行文字。为使文字更加突出,我们在文字周围显示白色填充的圆角矩形,并用化身颜色对其描边。我们使用画布的 measureText()方法来计算文本和圆角矩形的宽度。
6.背景
drawBackground 对象绘制一个渐变的蓝天和绿地。蓝天和绿地都被渐变为白色以给人一种三维的深度感。
7.初始化
initAndGo()函数执行各种设置工作,如建立事件处理程序、连接到服务器。最后它执行移动和绘制头像与文字的循环:
8.页面代码
下面是聊天应用程序的HTML页面布局,被保存在一个名为canvas-webSockets- chat.htm的文件中: