prosource

웹 페이지의 실시간 데이터를 구현하는 방법

probook 2023. 9. 5. 20:37
반응형

웹 페이지의 실시간 데이터를 구현하는 방법

(이 질문은 Q/A 스타일의 질문으로, 비슷한 질문을 하는 사람들에게 유용한 자료가 됩니다.많은 사람들이 모든 선택지를 모르기 때문에 이것을 하는 가장 좋은 방법을 찾는 것처럼 보입니다.대부분의 답은 ASP가 될 것입니다.NET에 따라 다르지만 AJAX 및 기타 기술은 socket.io 및 SignalR과 같은 다른 프레임워크에서 동등한 기능을 가지고 있습니다.)

ASP에서 구현한 데이터 표가 있습니다.NET. 이 기본 데이터에 대한 변경 사항을 실시간 또는 거의 실시간으로 페이지에 표시하고자 합니다.어떻게 해야 하나요?

내 모델:

public class BoardGame
    {
    public int Id { get; set;}
    public string Name { get; set;}
    public string Description { get; set;}
    public int Quantity { get; set;}
    public double Price { get; set;}

    public BoardGame() { }
    public BoardGame(int id, string name, string description, int quantity, double price)
        {
        Id=id;
        Name=name;
        Description=description;
        Quantity=quantity;
        Price=price;
        }
    }

이 예에서는 실제 데이터베이스 대신 응용프로그램 변수에 데이터를 저장합니다.나는 그것을 나의 것에 씨를 뿌릴 것입니다.Application_Start.asax.cs .http://Global.asax.cs 의 입니다.

var SeedData = new List<BoardGame>(){
    new BoardGame(1, "Monopoly","Make your opponents go bankrupt!", 76, 15),
    new BoardGame(2, "Life", "Win at the game of life.", 55, 13),
    new BoardGame(3, "Candyland", "Make it through gumdrop forrest.", 97, 11)
    };
Application["BoardGameDatabase"] = SeedData;

웹 양식을 사용하는 경우 데이터를 중계기로 표시할 수 있습니다.

<h1>Board Games</h1>
        <asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame">
            <HeaderTemplate>
                <table border="1">
                    <tr>
                        <th>Id</th>
                        <th>Name</th>
                        <th>Description</th>
                        <th>Quantity</th>
                        <th>Price</th>
                    </tr>
            </HeaderTemplate>
            <ItemTemplate>
                <tr>
                    <td><%#: Item.Id %></td>
                    <td><%#: Item.Name %></td>
                    <td><%#: Item.Description %></td>
                    <td><%#: Item.Quantity %></td>
                    <td><%#: Item.Price %></td>
                </tr>
            </ItemTemplate>
            <FooterTemplate></table></FooterTemplate>
        </asp:Repeater>

다음 코드에 데이터를 로드합니다.

protected void Page_Load(object sender, EventArgs e)
    {
    BoardGameRepeater.DataSource = Application["BoardGameDatabase"];
    BoardGameRepeater.DataBind();
    }

레이저를 사용한 MVC의 경우 모델별로 단순합니다.

@model IEnumerable<RealTimeDemo.Models.BoardGame>
<h1>Board Games</h1>
<table border="1">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Id)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Description)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Quantity)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
    </tr> 
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Id)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Description)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Quantity)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
    </tr>
} 
</table>

웹 양식을 사용하여 데이터를 추가할 수 있는 작은 페이지를 만들어 데이터 업데이트를 실시간으로 볼 수 있습니다.양식과 표를 동시에 볼 수 있도록 두 개의 브라우저 창을 만드는 것이 좋습니다.

<h1>Create</h1>
<asp:Label runat="server" ID="Status_Lbl" /><br />
Id: <asp:TextBox runat="server" ID="Id_Tb" /><br />
Name: <asp:TextBox runat="server" ID="Name_Tb" /><br />
Description: <asp:TextBox runat="server" ID="Description_Tb" /><br />
Quantity: <asp:TextBox runat="server" ID="Quantity_Tb" /><br />
Price: <asp:TextBox runat="server" ID="Price_Tb" /><br />
<asp:Button runat="server" ID="SubmitBtn" OnClick="SubmitBtn_Click" Text="Submit" />

그리고 그 이면의 코드는:

protected void SubmitBtn_Click(object sender, EventArgs e)
    {
    var game = new BoardGame();
    game.Id = Int32.Parse(Id_Tb.Text);
    game.Name = Name_Tb.Text;
    game.Description = Description_Tb.Text;
    game.Quantity = Int32.Parse(Quantity_Tb.Text);
    game.Price = Int32.Parse(Price_Tb.Text);
    var db = (List<BoardGame>)Application["BoardGameDatabase"];
    db.Add(game);
    Application["BoardGameDatabase"] = db;
    //only for SignalR
    /*var context = GlobalHost.ConnectionManager.GetHubContext<GameHub>();
    context.Clients.All.addGame(game); */           
    }

신호 R

이것은 가볍고 오늘날의 모바일(데이터가 제한된) 환경에서 잘 작동하는 훨씬 더 깔끔한 구현을 보여주기 때문에 제가 가장 기대하는 답변입니다.

서버에서 클라이언트로 데이터를 "실시간" 푸시(또는 데이터를 푸시하는 모양)하는 기능을 제공하는 여러 가지 방법이 있습니다.Rapid Short Polling(나의 AJAX 기반 응답과 유사), Long Polling, Forever Frame, Server Sent Events 및 WebSockets는 이를 위해 사용되는 서로 다른 전송 메커니즘입니다.SignalR은 클라이언트와 서버의 기능에 따라 적절한 전송 메커니즘을 선택할 수 있는 추상화 계층입니다.SignalR을 사용할 때의 가장 좋은 점은 간단하다는 것입니다.전송 메커니즘에 대해 걱정할 필요가 없으며 프로그래밍 모델은 이해하기 쉽습니다.

SignalR 허브를 정의할 것이지만 비워 둡니다.

public class GameHub : Hub
    {
    }

제가 "데이터베이스"에 데이터를 추가할 때, 저는 아래의 코드를 실행할 것입니다.질문을 읽으면 "만들기" 양식으로 설명한 것을 볼 수 있습니다.당신은 그것을 언급하고 싶을 것입니다.

var context = GlobalHost.ConnectionManager.GetHubContext<GameHub>();
context.Clients.All.addGame(game);

내 페이지 코드는 다음과 같습니다.

<h1>SignalR</h1>
        <asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame">
            <HeaderTemplate>
                <table border="1">
                    <thead>
                        <tr>
                            <th>Id</th>
                            <th>Name</th>
                            <th>Description</th>
                            <th>Quantity</th>
                            <th>Price</th>
                        </tr>
                    </thead>
                    <tbody id="BoardGameTblBody">
            </HeaderTemplate>
            <ItemTemplate>
                <tr>
                    <td><%#: Item.Id %></td>
                    <td><%#: Item.Name %></td>
                    <td><%#: Item.Description %></td>
                    <td><%#: Item.Quantity %></td>
                    <td><%#: Item.Price %></td>
                </tr>
            </ItemTemplate>
            <FooterTemplate></tbody></table></FooterTemplate>
        </asp:Repeater>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <script src="Scripts/jQuery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.1.1.min.js"></script>
        <script src="signalr/hubs"></script>
        <script type="text/javascript">
            var hub = $.connection.gameHub;
            hub.client.addGame = function (game) {
                $("#BoardGameTblBody").append("<tr><td>" + game.Id + "</td><td>" + game.Name + "</td><td>" + game.Description + "</td><td>" + game.Quantity + "</td><td>" + game.Price + "</td></tr>");
            };
            $.connection.hub.start();
        </script>

그리고 그 이면의 코드는:

protected void Page_Load(object sender, EventArgs e)
        {
        BoardGameRepeater.DataSource = Application["BoardGameDatabase"];
        BoardGameRepeater.DataBind();
        }

여기서 무슨 일이 일어나고 있는지 주목하세요.가 서가호할때출버때할을 호출할 때.context.Clients.All.addGame(game);할된기능실있습다니고행에 할당된 hub.client.addGame게임 허브에 연결된 모든 클라이언트에 적용됩니다.은 저를의 배선을 , 저의 SignalR을 합니다.game에서 서에개 대로으로 합니다.game클라이언트에 대한 개체입니다.그리고 무엇보다도, 몇 초마다 네트워크 트래픽이 오가지 않기 때문에 매우 가볍습니다.

장점:

  • 네트워크 트래픽이 매우 밝습니다.
  • 개발이 쉽지만 유연성이 있음
  • 요청과 함께 뷰 상태를 보내지 않습니다.
  • 서버를 지속적으로 폴링하지 않습니다.

할 수 .editedGame변경된 데이터를 클라이언트에 쉽게 푸시할 수 있습니다(삭제 시에도 동일).

타이머/업데이트 패널

웹 양식을 사용하는 경우 업데이트 패널이라는 컨트롤을 사용할 수 있습니다.업데이트 패널은 전체 페이지의 포스트백을 발생시키지 않고 페이지의 섹션을 비동기적으로 새로 고칠 수 있습니다.asp와 결합:타이머, 원하는 시간에 테이블을 업데이트할 수 있습니다.코드는 다음과 같습니다.

<asp:ScriptManager runat="server" />
        <h1>Board Games (using Update Panel)</h1>
        <asp:Timer runat="server" ID="UP_Timer" Interval="5000" />
        <asp:UpdatePanel runat="server" ID="Game_UpdatePanel">
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="UP_Timer" EventName="Tick" />
            </Triggers>
            <ContentTemplate>
                <asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame">
                    <HeaderTemplate>
                        <table border="1">
                            <tr>
                                <th>Id</th>
                                <th>Name</th>
                                <th>Description</th>
                                <th>Quantity</th>
                                <th>Price</th>
                            </tr>
                    </HeaderTemplate>
                    <ItemTemplate>
                        <tr>
                            <td><%#: Item.Id %></td>
                            <td><%#: Item.Name %></td>
                            <td><%#: Item.Description %></td>
                            <td><%#: Item.Quantity %></td>
                            <td><%#: Item.Price %></td>
                        </tr>
                    </ItemTemplate>
                    <FooterTemplate></table></FooterTemplate>
                </asp:Repeater>
            </ContentTemplate>
        </asp:UpdatePanel>

그리고 그 이면의 코드는:

    protected void Page_Load(object sender, EventArgs e)
        {
        BoardGameRepeater.DataSource = Application["BoardGameDatabase"];
        BoardGameRepeater.DataBind();
        }

이제 이것이 어떻게 작동하는지에 대해 이야기해 보겠습니다.5초마다 타이머가 Tick 이벤트를 실행합니다.이 서버는 업데이트 패널에 비동기 포스트백 서버로 등록되므로, 부분적인 포스트백이 발생하면 전체 페이지 수명 주기가 다시 실행되므로 페이지 로드 이벤트에서 데이터를 다시 로드한 다음 업데이트 패널의 내용 템플릿의 전체 내용이 서버에서 새로 생성된 데이터로 바뀝니다.네트워크 트래픽이 어떻게 표시되는지 살펴보겠습니다.

+5s Client => Server | Run the page lifecycle, send me the contents of the ContentPanel.
Server => Client | Here's the entire contents of the ContentPanel.
+10s Client => Server | Run the page lifecycle, send me the contents of the ContentPanel.
Server => Client | Here's the entire contents of the ContentPanel.
+15s Client => Server | Run the page lifecycle, send me the contents of the ContentPanel.
Server => Client | Here's the entire contents of the ContentPanel.

장점:

  • 구현이 간단합니다.타이머, 스크립트 관리자를 추가하고 리피터를 업데이트 패널로 감싸기만 하면 됩니다.

단점:

  • 헤비: 요청할 때마다 ViewState가 서버로 전송됩니다.그러나 ViewState를 사용하지 않도록 설정하면 이 영향이 가벼워질 수 있습니다.
  • 헤비: 데이터가 변경되었는지 여부에 관계없이 모든 데이터를 5초마다 라인을 통해 전송합니다.그것은 엄청난 대역폭입니다.
  • 저속: 모든 데이터가 와이어를 통과하기 때문에 각 부분적인 포스트백에 시간이 오래 걸립니다.
  • 작업하기 어려움:더 많은 기능을 추가하기 시작하면 부분 포스트백을 올바르게 처리하기가 어려울 수 있습니다.
  • Not smart: 이전 요청이 완료되지 않았더라도 타이머 덕분에 계속해서 다시 게시됩니다.
  • 똑똑하지 않음: 네트워크 중단을 처리하는 쉬운 방법이 없습니다.

AJAX 폴링, 구현 개선

다른 AJAX 기반 답변과 마찬가지로 서버를 지속적으로 폴링할 수 있습니다.하지만 이번에는 표시할 데이터로 응답하는 대신, 데이터의 ID 목록으로 응답할 것입니다.클라이언트 측은 어레이에서 이미 검색한 데이터를 추적한 다음 새 ID가 추가된 것을 확인하면 서버에 별도의 GET 요청을 보냅니다.

페이지 코드는 다음과 같습니다.

<h1>Board Games (AJAX Polling Good)</h1>
        <table id="BoardGameTbl" border="1">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Description</th>
                    <th>Quantity</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody id="BoardGameTblBody">
            </tbody>
        </table>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <script type="text/javascript">
            var loadedGames = [];
            function getListOfGames() {
                $.ajax({
                    type: "GET",
                    url: "api/GamesApi/GetGameIds",
                    dataType: "json"
                })
                .done(function (data) {
                    for (i = 0; i < data.length; i++) {
                        if (loadedGames.indexOf(data[i]) == -1) {
                            loadedGames[loadedGames.length] = data[i];
                            getGame(data[i]);
                        }
                    }
                    setTimeout(getListOfGames, 5000);
                });
            }
            function getGame(id) {
                $.ajax({
                    type: "GET",
                    url: "api/GamesApi/GetGame/" + id,
                    dataType: "json"
                })
                .done(function (game) {
                    $("#BoardGameTblBody").append("<tr><td>" + game.Id + "</td><td>" + game.Name + "</td><td>" + game.Description + "</td><td>" + game.Quantity + "</td><td>" + game.Price + "</td></tr>");
                });
            }
            getListOfGames();
        </script>

웹 API 컨트롤러는 다음과 같습니다.

namespace RealTimeDemo.Controllers
{
public class GamesApiController : ApiController
    {
    [Route("api/GamesApi/GetGameIds")]
    public IEnumerable<int> GetGameIds()
        {
        var data = HttpContext.Current.Application["BoardGameDatabase"] as List<BoardGame>;
        var IDs = data.Select(x => x.Id);
        return IDs;
        }

    [Route("api/GamesApi/GetGame/{id}")]
    public BoardGame GetGame(int id)
        {
        var data = HttpContext.Current.Application["BoardGameDatabase"] as List<BoardGame>;
        return data.Where(x => x.Id == id).SingleOrDefault();
        }
    }

이것은 제 다른 AJAX 기반 답변과 타이머/업데이트 패널 답변보다 훨씬 더 나은 구현입니다.ID는 5초마다 전송되므로 네트워크 리소스에 대한 부담이 훨씬 적습니다.또한 네트워크 연결 상황을 처리하지 않거나 새 데이터가 로드될 때 알림을 실행하는 것(예: 메모 토오)도 매우 사소한 일입니다.

이점

  • 요청과 함께 뷰 상태를 보내지 않습니다.
  • 전체 페이지 수명 주기를 실행하지 않음
  • 폴링의 일부로 ID만 유선으로 전송됩니다(요청과 함께 타임스탬프를 보내고 타임스탬프 이후 변경된 데이터로만 응답하는 경우 개선될 수 있습니다).새 개체만 데이터베이스에서 검색됩니다.

단점 - 여전히 폴링 중이며, 몇 초마다 요청을 생성하고 있습니다.데이터가 자주 변경되지 않으면 대역폭을 불필요하게 사용하게 됩니다.

AJAX 폴링, 구현 불량

MVC 또는 웹 양식을 사용하는 경우 AJAX 폴링이라는 기술을 구현할 수 있습니다.그러면 AJAX 요청이 서버로 계속 전송됩니다.서버가 최신 데이터를 포함하는 응답을 보냅니다.그것은 실행하기가 믿을 수 없을 정도로 간단합니다.AJAX를 사용하기 위해 jQuery를 사용할 필요는 없지만 훨씬 더 쉽게 사용할 수 있습니다.이 예제에서는 서버 측 기능에 웹 API를 사용합니다.웹 API는 MVC와 유사하며 라우팅 및 컨트롤러를 사용하여 요청을 처리합니다.ASMX서비스를 대체합니다.

이것은 웹 양식 코드이지만 MVC 코드와 매우 유사하기 때문에 생략하겠습니다.

<h1>Board Games (AJAX Polling Bad)</h1>
        <table id="BoardGameTbl" border="1">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Description</th>
                    <th>Quantity</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody id="BoardGameTblBody">
            </tbody>
        </table>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <script type="text/javascript">
            function getData() {
                $.ajax({
                    type: "GET",
                    url: "api/GamesApi/GetGameData",
                    dataType: "json"
                })
                .done(function (data) {
                    $("#BoardGameTblBody").empty();
                    for (i = 0; i < data.length; i++) {
                        $("#BoardGameTblBody").append("<tr><td>" + data[i].Id + "</td><td>" + data[i].Name + "</td><td>" + data[i].Description + "</td><td>" + data[i].Quantity + "</td><td>" + data[i].Price + "</td></tr>");
                    }
                    setTimeout(getData, 5000);
                });
            }
            getData();
        </script>

웹 API에 대한 요청입니다.API는 모든 게임의 JSON 표현을 반환합니다.

public class GamesApiController : ApiController
    {
    [Route("api/GamesApi/GetGameData")]
    public IEnumerable<BoardGame> GetGameData()
        {
        var data = HttpContext.Current.Application["BoardGameDatabase"] as List<BoardGame>;
        return data;
        }
    }

이 방법의 전반적인 결과는 타이머/업데이트 패널 방법과 유사합니다.그러나 요청과 함께 뷰 상태 데이터를 보내지 않으며 긴 페이지 수명 주기 프로세스를 실행하지 않습니다.여러분은 또한 여러분이 포스트백에 있는지 없는지, 혹은 부분적인 포스트백에 있는지 없는지를 감지하면서 춤을 출 필요가 없습니다.따라서 타이머/업데이트 패널에 비해 향상된 기능이라고 생각합니다.

그러나 이 방법은 여전히 타이머/업데이트 패널 방법의 주요 단점 중 하나입니다.당신은 여전히 각 AJAX 요청과 함께 모든 데이터를 유선으로 보내고 있습니다.제 다른 AJAX 기반 답변을 보시면 AJAX 폴링을 구현하는 더 나은 방법을 보실 수 있습니다.

이점

  • 요청과 함께 뷰 상태를 보내지 않습니다.
  • 전체 페이지 수명 주기를 실행하지 않음

단점들

  • 몇 초마다 요청을 생성합니다.
  • 응답에는 변경되지 않은 모든 데이터가 포함됩니다.

언급URL : https://stackoverflow.com/questions/25829343/how-to-implement-real-time-data-for-a-web-page

반응형