jQuery Grid, WebSockets 및 KnockoutJS를 사용한 라이브 데이터
효과적이고 기능적인 응용 프로그램을 갖는 유일한 목적으로 라이브 데이터와 같이 실시간으로 클라이언트를 업데이트하는 유일한 방법이 라이브 인 것처럼 보이는 수많은 시나리오가 있습니다.
효과적이고 기능적인 응용 프로그램을 갖는 유일한 목적으로 라이브 데이터와 같이 실시간으로 클라이언트를 업데이트하는 유일한 방법이 라이브 인 것처럼 보이는 수많은 시나리오가 있습니다.
그냥 그렇게 일이 이루어져야 하는 것처럼 느껴집니다. 사용자 자신은 동적 웹 응용 프로그램에 거의 익숙해졌습니다. 상상력을 발휘하기 위해 아래에 시연된 응용 프로그램의 스크린샷이 있습니다(이 고요함은 실제로 정의되지 않는다는 점을 명심하십시오).

그러나 이러한 앱을 제공하는 기능은 jQuery 위젯과 같은 클라이언트 측 논리 또는 서버의 일부 도움말(따라서 통신)에 의존합니다. 이에 대한 올바른 용어는 '폴링'(Wikipedia에서 자세한 내용을 보려면 여기를 참조하십시오)이며 클라이언트가 서버에 "아직 새로운 것이 있습니까?"라고 지속적으로 묻는 프로세스입니다. 그리고 그것은 계속해서 일어납니다. 문제는 추가 트래픽을 생성하고 서버가 "아니오"라고 말하기 위해 많은 요청을 처리하도록한다는 것입니다. 그것은 푸시 기술(또는 간단히 말해서 알림)과 함께 과거의 일(모바일 장치를 보는 것)이 될 수 있습니다. 모바일 OS는 이러한 서비스를 지원하며(Apple 및 Windows Phone 푸시 알림이라고 부르고, Android는 이러한 클라우드를 장치 메시징이라고 함) 몇 가지 기술(예: 연결을 닫지 않고 루프에서 열어 두는 HTML 스트리밍)이 있습니다. 그런 다음 또 있습니다....
WebSockets
WebSocket은 전이중(full-duplex), 즉 비차단 동시 양방향 통신을 제공하는 웹 기술입니다. 물론 API와 함께 제공되며 클라이언트와 서버 모두에서 사용할 수 있습니다. 프로토콜 자체에는 몇 가지 변경 사항이 있으며 IETF에 의해 RFC 6455로 표준화되었습니다. 단일 TCP 연결(하나의 소켓)을 통해 양방향 전송을 유지할 수 있는 기능은 연결 수를 줄여주기 때문에 매우 매력적입니다. 그리고 예, 위에서 설명한 문제에 따라 WebSocket 프로토콜은 요청하거나 폴링할 필요 없이 클라이언트로 데이터를 보낼 수 있는 수단을 서버에 제공할 수 있습니다. 이것이 제가 이 블로그에서 보여드리고자 하는 것입니다 – 멋진 앱을 위한 두 가지 인기 있는 클라이언트 컨트롤과 함께 이 프로토콜을 구성하는 방법입니다. 이제 프로토콜이 변경 사항을 거쳤기 때문에 여전히 최신 상태가 아닌 많은 구현이 있습니다. 브라우저는 모든 브라우저가 프로토콜을 지원하는 것은 아니기 때문에 또 다른 문제입니다 (Chrome과 Firefox는 곧 IE10이 될 것입니다). 그것은 여전히 브라우저의 꽤 괜찮은 덩어리이며, 당신에게 충분하다면 최신 버전에서 몇 가지 보안 트릭이 있는 눈에 거슬리지 않는 연결의 이점을 누릴 수 있습니다. 나는 꽤 멋진 .NET 또는 Node.js 구현을 보았고 분명히 당신은 당신이 선택한 언어에 적합한 것을 찾을 것입니다. .NET 프레임워크 4.5에는 'System.Net.WebSockets '라는 새롭고 반짝이는 네임스페이스도 있습니다! 필자는 프레임 워크 업데이트가 필요하지 않고 이전 버전과 함께 최신 버전 (최신 Chrome 또는 Firefox 브라우저에서 찾을 수있는 버전)을 지원하기 때문에 오픈 소스 구현을 선택했습니다. SuperWebSocket이라고 하며 CodePlex: http://superwebsocket.codeplex.com/에서 찾을 수 있습니다. 제 경우에는 서버 측이 내 데모를 지원하기 위해 여기에 있으므로 구현이 완벽하지 않거나 실제로 대규모로 사용할 수 없다는 점을 명심하십시오. 서버는 확장 가능한 프레임 워크를 기반으로하므로 데모에서 몇 가지 참조를 찾을 수 있습니다.

다음은 구성 섹션과 초기화입니다.
<configuration>
<configSections>
<section name="socketServer" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
</configSections>
<socketServer>
<servers>
<server name="SuperWebSocket"
serviceName="SuperWebSocket"
ip="Any" port="2011" mode="Sync">
</server>
</servers>
<services>
<service name="SuperWebSocket"
type="SuperWebSocket.WebSocketServer, SuperWebSocket" />
</services>
</socketServer>
<!--The rest is omitted-->
이것은 물론 응용 프로그램 시작 (이벤트 또는 서버 환경이 제공하는 것과 동등한 것)에 한 번만 호출됩니다. . 또한 이벤트를 연결하고 연결 및 데이터 전송을 매우 쉽게 처리 할 수 있습니다. 다음은 뷰 자체가 아닌 세션을 설정할 때 초기 데이터(로컬 Northwind 데이터베이스에서 생성된 LINQtoSQL 클래스에서 가져옴)를 클라이언트로 보내는 방법입니다.
private void StartWebSockServ()
{
SocketServiceConfig config = ConfigurationManager.GetSection("socketServer") as SocketServiceConfig;
// initialize with the above configuration
if (!SocketServerManager.Initialize(config))
return;
// get an instance and set up:
var socketServer = SocketServerManager.GetServerByName("SuperWebSocket") as WebSocketServer;
HttpContext.Current.Application["WebSocketPort"] = socketServer.Config.Port;
//set up the event handlers
socketServer.NewSessionConnected += new SessionEventHandler<WebSocketSession>(Controllers.HomeController.socketServer_NewSessionConnected);
socketServer.SessionClosed += new SessionEventHandler<WebSocketSession, SuperSocket.SocketBase.CloseReason>(Controllers.HomeController.socketServer_SessionClosed);
socketServer.NewDataReceived += new SessionEventHandler<WebSocketSession, byte[]>(Controllers.HomeController.socketServer_NewDataReceived);
socketServer.NewMessageReceived += new SessionEventHandler<WebSocketSession, string>(Controllers.HomeController.socketServer_NewMessageReceived);
if (!SocketServerManager.Start())
SocketServerManager.Stop();
//start ticking data broadcast
Controllers.HomeController.timer = new Timer(new TimerCallback(Controllers.HomeController.DataBroadcastOnChange));
Controllers.HomeController.timer.Change(10000, 10000);
}
아시다시피 저는 실제로 라이브 데이터가 없기 때문에 (그리고 트위터 / 페이스 북 리더를 만드는 느낌이 들지 않았습니다) 간단한 시간 제한 이벤트에 상주하고 데이터에서 임의의 변경 사항을 생성했으며 그 부분은 생략하겠습니다. 실제 애플리케이션에서는 다음이 데이터 계층의 일부 이벤트를 처리해야 합니다.
public static void socketServer_NewSessionConnected(WebSocketSession session)
{
NorthWindDataContext nw = new NorthWindDataContext();
JavaScriptSerializer serializer = new JavaScriptSerializer();
session.SendResponse(serializer.Serialize(nw.Sales_by_Categories.Take(20)));
}
이것은 기본적으로 서버에서 데이터를 푸시하는 데 필요한 모든 것이지만 여전히 수신 된 메시지를 처리하여 양방향 연결 및 ... 예를 들어, 한 클라이언트에서 변경한 사항을 저장하고 다른 모든 클라이언트로 보냅니다!
클라이언트
WebSocket 통신을 처리하기 위한 클라이언트 측 구현은 매우 간단하며 서버의 이벤트 논리(연결됨/데이터 수신/연결 해제됨)를 다소 따릅니다.
public static void DataBroadcastOnChange(object state)
{
//pretend we got changes from some service while really generating randoms:
List<Sales_by_Category> changes = GetDataChanges();
//send it back to the clients
WebSocketServer socketServer = SocketServerManager.GetServerByName("SuperWebSocket") as WebSocketServer;
var sessions = socketServer.GetAllSessions();
JavaScriptSerializer serializer = new JavaScriptSerializer();
//broadcast the changes to all clients (if any)
foreach (WebSocketSession session in sessions)
{
session.SendResponse(serializer.Serialize(changes));
}
}
포트는 서버 구성과 동일하며 수신하는 데이터는 'onmessage' 이벤트의 event 매개 변수에 있습니다. 데이터를 처리하기 전에 데이터로 무엇을 해야 할지 고려하는 시점이므로 몇 가지 준비가 필요합니다. 목표는 살아 있다고 느끼는 클라이언트가 있는 응용 프로그램이고 우리는 이미 기본 데이터 공급 배관을 제공했지만 초기 데이터를 표시하는 것만으로는 제대로 되지 않습니까? 물론 우리는 강력한 jQuery Grid를 사용하여이를 수행 할 수 있으며 초기 데이터를 버리고 새 데이터를 순식간에 표시하는 것을 주저하지 않을 것이지만 이는 매우 우아한 해결책이 아니며 위의 힌트는 이미 모든 것이 아닌 변경된 레코드를 다시 보내고 싶다는 힌트입니다. 따라서 우리는 12.1과 함께 제공되는 Infragistics jQuery 도구 세트에 대한 몇 가지 깔끔한 추가 기능을 활용할 수 있습니다.
Knockout!
Knockout.js는 MVVM 디자인 패턴을 지원하고 동적 UI 생성을 단순화하며 데모 프로젝트에 완벽하게 만드는 JavaScript 라이브러리입니다. 그것이 무엇인지, 무엇을 할 수 있는지 살펴보고 싶다면 http://knockoutjs.com/ 많은 라이브 예제와 튜토리얼을 확인하십시오. 무엇보다도 사이트에서 가져올 수있는 라이브러리 (매핑도 가져 오는지 확인)가 필요하거나 NuGet도 다운로드 할 수 있습니다. 그런 다음 코드에 jQuery (및 UI)와 함께 스크립트에 대한 링크를 추가하고 자체 Loader 위젯을 추가하십시오. 이제 모델을 만들 차례입니다 – 이미 언급했듯이 Northwind의 데이터를 사용하고 있으며 이는 'Sales by Category' 뷰이며 여기에 포함된 데이터 형식입니다.
$(document).ready(function () {
//web socket handling
if ('WebSocket' in window) {
connect('ws://localhost:2011/');
}
else {
alert("WebSockets don't seem to be supported on this browser.");
}
function connect(host) {
ws = new WebSocket(host);
ws.onopen = function () {
notify('Connected!');
};
ws.onmessage = function (evt) {
// handle data in evt.data
};
ws.onclose = function () {
notify('Socket connection was closed!!!');
};
};
});
그런 다음 다음과 같이 이러한 항목의 관찰 가능한 컬렉션을 사용하여 뷰 모델을 만듭니다.
function Item(categoryID, categoryName, productName, productSales) {
//the unique key here is the prodcut name!
return {
categoryID: ko.observable(categoryID),
categoryName: ko.observable(categoryName),
productName: ko.observable(productName),
productSales: ko.observable(productSales)
};
};
'jsonData'는 서버에서 데이터를 가져올 때 채워지며 자세한 내용은 아래에서 설명합니다. 지금까지 데이터와 모델이 있으며 다음을 추가하여 UI를 만들 수 있습니다.
그리드
먼저 로더 위젯을 설정하고 이번에는 그리드를 제외하고 knockout.js 지원을 위해 두 확장 파일에 대한 경로를 추가합니다.
function ItemsViewModel() {
var self = this;
self.data = ko.observableArray([]);
for (var i = 0; i < jsonData.length; i++) {
self.data.push(new Item(jsonData[i].CategoryID, jsonData[i].CategoryName, jsonData[i].ProductName, jsonData[i].ProductSales));
}
}
녹아웃 지원을 위해 업데이트 기능이 *필요합니다*. 이제 Knockout의 "data-bind" 속성을 사용하여 Grid를 정의할 수 있습니다.
$.ig.loader({
scriptPath: "../../Scripts/js/",
cssPath: "../../Content/css/",
resources: "igGrid.Updating,extensions/infragistics.datasource.knockoutjs.js,extensions/infragistics.ui.grid.knockout-extensions.js"
});
보시다시피 그리드 정의 스타일은 괄호 안에 동일하게 유지되며 생성된 후에는 일반적으로 사용하는 모든 API 메서드를 사용할 수 있습니다.
모든 것을 함께 바인딩
물론 이제 해야 할 일은 데이터를 모델에 공급하고 Knockout과 Grid가 나머지를 처리하도록 하는 것입니다. 그래도 분명히 해야 할 몇 가지 사소한 사항이 있습니다. 첫째, 언급 한대로 임의의 변경 사항을 생성하고 있으며 동일한 연결을 통해 변경된 항목 만 보내고 싶기 때문에 서로 구별 할 수있는 방법이 필요했기 때문에 업데이트를 표시하기 위해 빈 첫 번째 레코드를 추가합니다 (데이터베이스에서 가져올 수없는 null 기본 키 확인). 그러나 그것은 나의 빠르고 더러운 해결책이며, 당신은 자신 만의 것을 가질 수 있거나 업데이트에만 WebSocket 연결을 사용할 수 있습니다. 아래 스 니펫에서 기본 키를 제공하여 컬렉션에서 항목 ID를 가져 오는 데 사용되는 Knockout 유틸리티 도구 세트 중 일부가 작동하는 것을 볼 수 있으며, 업데이트 된 셀을 가져 오는 데 사용되는 일부 그리드 API를 사용하고 값이 방금 변경되었음을 사용자에게 분명히하기 위해 약간 번쩍입니다. WebSocket 'onmessgae' 이벤트는 이제 다음과 같습니다.
<table id="grid"
data-bind="igGrid: {
dataSource: data, width: 650, primaryKey: 'productName', autoCommit: true,
features: [ {
name: 'Updating', editMode: 'row',
},
{
name: 'Paging', pageSize: 10,
}
],
enableHoverStyles: false,
autoGenerateColumns: false,
columns: [
{key: 'categoryID', headerText: 'Category ID', width: 100, dataType: 'number'},
{key: 'categoryName', headerText: 'Category Name', width: 200, dataType: 'string'},
{key: 'productName', headerText: 'Product Name', width: 130, dataType: 'string'},
{key: 'productSales', headerText: 'Sales', width: 170, dataType: 'number'}
]}"></table>
사용자 정의 알림 기능 및 일부 CSS 스타일과 같은 몇 가지 사소한 조정을 제외하고, 이것이 앱을 만든 것입니다. 그리고 연결(초기 이후)이 업데이트에 사용되기 때문에 연결이 끊어지더라도 큰 문제가 되지 않습니다 – 우리가 정의한 이벤트 처리에 따라 결과는 다음과 같습니다.

그러나 다시 그리드는 계속 작동하며 이 앱을 균형 잡히고 기능적으로 만들기 위해 다시 연결을 시도하는 방법을 제공할 수 있습니다.
마무리
WebSocket 연결로 처리되는 라이브 데이터 피드, 관찰 가능 항목 기반 KnockoutJS 모델 및 이를 밟고, 변경 사항을 동적으로 표시 및 반영하는 jQuery Grid를 사용하여 모션 필드로 가득 찬 애플리케이션을 만드는 방법을 살펴보았습니다.
스크린샷은 여기에서 자르지 않기 때문에 곧 제공될 작은 비디오가 있으며 2012년 첫 번째 릴리스가 사실인 데모 프로젝트가 사실입니다. 지켜!