基于SingalR 的Web实时应用程序框架设计
2015-12-20刘黎志
刘黎志
(1.武汉工程大学 智能机器人湖北省重点实验室,湖北 武汉430205;2.武汉工程大学 计算机科学与工程学院,湖北 武汉430205)
0 引 言
随着移动互联网应用的迅速发展,传统的客户端浏览器与服务器之间通过请求/应答的方式获取信息的方式已经不能满足用户对数据实时更新的要求,用户希望更新的数据能够实时推送到自己的桌面、手机或平板上,而不需要手动更新[1-4]。HTML5 WebSocket可 以 取 代Comet的Long Pooling及Forever Frame技术,使得服务器和客户端浏览器之间具有实时通讯能力。由于WebScoket连接实际上就是TCP连接,所以基于WebSocket开发的实时应用程序可以在数据传输稳定性及数据传输量上得到极大提升[5-8]。微软的SingalR通过兼容Comet及HTML5 Web Socket,结合OWIN (open Web interface for.NET)、Ajax、JQuery等技术,提供给开发人员一个先进的Web实时应用程序开发平台。
1 SingalR
SingalR是一组可实现Web实时应用程序的组件集合,SingalR 抽象了应用程序客户端和服务端之间的传输协议,SingalR 支持HTML5的WebSocket,Server Send Event协议及Comet的Ajax Long Pooling,Forever Frame协议[9]。SingalR 根据服务端及客户端的不同配置环境,如浏览器类型及版本、操作系统类型,用户配置等自动选择传输协议。在选择传输协议的过程中,SingalR 会尽量使用HTML5的WebSocket协议,使用WebSocket协议可以最有效地利用服务端内存,获得最低的传输延迟及完全的服务端与客户端的双工通信,但使用WebSocket协议要求服务端的操作系统 必 须 是Windows Server 2012 或Windows 8,且 支 持.Net Framework 4.5。客户端必须是最新版的Microsoft Internet Explorer,Google Chrome或Mozilla Firefox浏览器。
SingalR 在服务端和客户端之间建立永久的连接,服务端可以通过远程过程调用 (RPC)的方式调用客户端的Javascipt函数,从而使得服务端可以主动推送消息到所有的连接客户端,或特定的客户端。而不需要客户端按传统的请求-应答 (request-response)刷新页面获取最新数据。客户端则利用SingalR Hub上下文代理类调用服务端函数。服务端与客户端相互调用的过程如图1所示。
图1 服务端客户端相互调用
SingalR 负责维护所有与服务端连接的客户端,新加入的客户端及退出的客户端,SingalR 是可以自动感知的,从而使得服务端的更新可以实时的推送到所有客户端。SingalR 提供两种永久链接及Hub两种方式连接服务端及客户端,永久链接提供PersistentConnection类供开发人员以类似于WCF (windows communication foundation)的方式进行相互方法调用,而Hub则提供更抽象的调用通道进行双向方法调用,使得服务端及客户端都可以像调用本地方法一样调用对方的方法,同时支持强类型的参数传递及模型绑定。服务端与客户端的连接方式及传输协议如图2所示。
图2 服务端与客户端的连接方式及传输协议
2 Web实时应用程序框架
Web实时应用程序一般需要处理3种场景:①客户端调用服务端方法获取数据集合,并使用HTML 将数据集合在客户端浏览器中展示,服务端方法不需要广播调用其它连接的客户端方法更新客户端页面,该场景用于一个新的客户端连接到SingalR Hub时。②客户端调用服务端方法更新应用程序状态、执行业务逻辑等操作,导致应用程序数据、状态、业务规则发生变化,从而需要从服务端广播调用所连接的客户端方法,以反映这些改变,该场景用于用户与客户端页面进行交互,操作业务逻辑时。③服务端定时将数据更新发送到所连接的客户端,需要从服务端广播调用所连接的客户端方法,从而反应数据更新,该场景用户服务端主动推送数据到客户端的情况,不需要客户端主动请求,如股票数据的实时变化、Web浏览器实时聊天等。本文提出的Web 实时应用程序框架基于SingalR 的WebSocket传输协议及Hub连接方式,能满足上述3种场景的功能需求。
2.1 Web实时应用程序框架设计
当客户端浏览器向服务端实时应用程序发出连接请求时,SingalR在客户端与服务端之间建立永久的连接,并使用WebSocket进行双工通讯。连接完成后,OWIN (open Web interface for.NET)的Startup.cs类负责启动服务端与客户端之间SingalR Hub上下文路由,服务端与客户端的双向方法调用及结果返回通过SingalR Hub上下文完成[10]。
客户端调用服务端方法需要通过调用SingalR Hub类的实例方法,但SingalR Hub实例类只在客户端连接到服务端时,瞬间在服务端内存中存在,所以处理上述3类场景的方法不能在SingalR Hub实例类中定义,而需要在单独的业务逻辑类中定义,并且要求该业务逻辑类实例在应用程序的生命周期中为唯一且静态只读的,以便每个SingalR Hub类实例可以访问该实例,从而调用其实例方法。为使得业务逻辑类实例可以通过SingalR Hub调用客户端脚本方法,需要有当前所有客户端连接的实例引用,该实例引用可以通过GlobalHost.ConnectionManager.GetHubContext<T>().Clients得到,ConnectionManager负责动态维护当前的客户端连接,即新的客户端加入及存在的客户端断开连接,ConnectionManager是可以动态感知的,并返回反映当前实际客户端连接数量的Clients实例引用。唯一且静态只读的业务逻辑类实例由BizService类中的Instance属性反映,BizServiceHub的_biz属性在构造函数中被赋值,从而获得业务逻辑类实例引用。
业务逻辑静态类实例通过异步的方式访问数据、Web服务、WCF数据服务及其它数据源获取原始或更新的数据,提高了程序的性能及伸缩性。由于业务逻辑静态类实例中的方法代码有可能被多个线程访问,故含写操作的代码均是以线程安全的方式实现的。Web实时应用程序框架如图3所示。
图3 Web实时应用程序框架
2.2 Web实时应用程序框架实现
Web实时应用程序框架由OWIN Startup 类、BizService类、BizServiceHub 类 及 客 户 端 的BizService.js 脚 本组成。
2.2.1 OWIN Startup类
OWIN (open Web interface for.NET)定 义 了.NET Web服务器与Web应用程序之间的抽象接口。Web应用程序开发者可以利用OWIN 作为中间件将Web服务器与应用程序分离,从而使得Web应用程序可以以不同的方式作为其宿主发布,宿主可以是自宿主方式,IIS方式或Windows服务方式。OWIN 的另一个优势是,Web应用程序不再依赖于某个具体版本的Framework,从而使得应用程序和依赖组件之间的关系是可动态组合的。
OWIN 的Startup.cs类负责在客户端及服务端之间注册SingalR 中间件,该中间件负责定义客户端连接服务端SingalR Hub上下文的路由。在应用程序启动时,通过调用OwinExtensions类的扩展方法MapSignalR 方法实现。Startup.cs的定义如下所示。
?
2.2.2 BizService类
在服务端执行读取数据、改变应用程序状态、执行业务逻辑及定时推送更新数据到客户端的业务逻辑服务类BizService的定义如下所示。
?
由于业务逻辑服务类中的代码会被多个线程访问,将应用程序数据对象集合_data 定义为ConcurrentDictionary<string,Data>保证了数据集合对象的线程安全。执行业务逻辑及改变应用程序状态的代码段也需要是线程安全的,所以反映应用程序当前状态的_state变量类型为volatile类型,ChangeAppState方法代码段的第一行必须获取_updateStatelock对象锁。由于应用程序的数据源可能是关系数据库、Web服务、WCF数据服务及其它数据源,所以获取数据的getDatas方法应是异步执行的,以提高程序的性能。
2.2.3 BizServiceHub类
供客户端进行服务端方法调用的SingalR Hub上下文BizServiceHub类定义如下所示。
?
2.2.4 BizService.js脚本
执行用户界面交互事件、调用服务端方法及服务端广播调用方法的客户端脚本BizService.js定义如下所示。客户 端 脚 本 需 引 用jquery-1.10.0.min.js,jquery.signalR-2.0.0.js以上版本脚本库及系统动态生成的signalr/hubs脚本库。
?
2.3 Web实时应用程序场景执行过程
客户端获取初始数据的场景的执行过程为:①得到服务端BizServicHub类在客户端的代理对象biz。②客户端连接到服务端的SingalR 上下文,并完成Hub连接初始化后,按biz.server.getAllDatas()格式调用服务端BizServicHub类的GetAllDatas方法,注意客户端的方法名的第一个字符为小写。③服务端的BizServicHub实例调用业务逻辑类实例的GetAllDatas方法返回数据。④客户端获取数据集合,并调用DisplayData()方法显示数据。
客户端执行业务逻辑或改变应用程序状态的场景的执行过程为:①客户端连接到服务端的SingalR 上下文,并完成Hub连接初始化。②由客户端触发事件如Click,在事件中按biz.server.changeAppState (state)格 式 调 用 服 务 端BizServicHub类的ChangeAppState方法,并传入参数。③服务端的BizServicHub 实例调用业务逻辑类实例的ChangeAppState方法执行业务逻辑或改变应用程序状态。完成后,按Clients.All.changeAppStateClient(state)格式广播调用所有客户端的changeAppStateClient方法。④SingalR Hub上下文负责通知所有的连接客户端执行change-AppStateClient逻辑。
服务端定时推送数据到客户端场景的执行过程为:①服务端业务逻辑类实例中的Timer组件根据updateInterval定义的时间间隔,定时调用UpdateDatas方法。②getData()通过异步调用从数据源获取到更新的数据后,按Clients.All.updateDataClient(data)格式广播调用所有客户端的updateDataClient方法,并循环传递更新的数据对象。③SingalR Hub上下文负责通知所有的连接客户端执行updateDataClient逻辑。
3 结束语
HTML5带来的本地存储、WebSocket、图形及多媒体应用、支持多设备及跨平台、自适应页面等技术,正在深刻的改变传统的Web应用程序开发的模式,WebSocket正在逐步取代Comet技术,成为Web实时应用程序开发的主流技术。Web实时应用程序的框架设计还需要考虑以下两个问题:客户端的频繁更新及服务端的资源争用。客户端频繁更新问题突出表现在Web实时多人对战游戏中,在游戏过程中,多个用户会频繁的改变状态及更新数据,Web实时应用程序的框架设计需要及时的将状态和数据的变化在服务端处理后,再实时反馈到所有连接的客户端。资源争用表现在如何合理的调度服务端资源处理来自众多客户端的WebSocket连接、业务逻辑执行、数据存储及更新等请求。怎样更好的处理这两个问题,将是后续研究的重点方向。
[1]Yan Zhangling,Dai Mao.A real-time group communication architecture based on WebSocket [J].International Journal of Computer and Communication Engineering,2012,2 (1):408-411.
[2]Panagiotakis S,Kapetanakis K.Architecture for real time communications over the Web [J].International Journal of Web Engineering,2013,2 (1):1-8.
[3]Ma Kun,Sun Runyuan.Introducing WebSocket-based realtime monitoring system for remote intelligent buildings [J].International Journal of Distributed Sensor Networks,2013:1-10.
[4]JASRI,Kouto,Sayo-cho Hyogo.Web-based control application using WebSocket [C]//Proceedings of ICALEPCS,2011:673-675.
[5]ZHANG Yanzhao,CHEN Shaohong.Real time control system based on smart phone platform [J].Computer Applications and Software,2013,30 (7):236-239 (in Chinese). [张 延召,陈少红.基于智能手机平台的实时控制系统 [J].计算机应用与软件,2013,30 (7):236-239.]
[6]WU Xiaodong,WANG Peng.Research on communication mechanism and efficiency of Html5 [J].Journal of Changchun University of Science and Technology (Natural Science Edition),2011,34 (4):159-163 (in Chinese). [吴晓东,王鹏.Html5的通信机制及效率的研究 [J].长春理工大学学报(自然科学版),2011,34 (4):159-163.]
[7]Nikolai Qveander.Pushing real time data using HTML5 Web Sockets [D].Sweden:UMEA University Department of Computing Science,2011.
[8]Pavel Smolka.Real-time communication in web browser[D].Czech Republic:MASARYK University Faculty of Informatics,2013.
[9]Patrick Fletcher.Introduction to SignalR [EB/OL].[2014-06-10].http://www.asp.net/signalr/overview/signalr-20/gettingstarted-with-signalr-20/introduction-to-signalr.
[10]Howard Dierking.An overview of project katana [EB/OL].[2013-08-30].http://www.asp.net/aspnet/overview/owinand-katana/an-overview-of-project-katana.