Pokazywanie postów oznaczonych etykietą websocket. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą websocket. Pokaż wszystkie posty

poniedziałek, 15 grudnia 2014

[C#|Visual Studio] ASP .NET SignalR: Wprowadzenie

ASP .NET SignalR to genialny framework rozwiązujący problem notyfikacji serwerowych i komunikacji typu push. Wraz z rozwojem sieci i technologii z nią związanych, pojawia się potrzeba tworzenia serwisów dostarczających dane użytkownikom "w czasie rzeczywistym" i takich, które będą w stanie same dostarczać dane na dowolne urządzenie (przeglądarka, desktop, aplikacje mobilne). Całą sieć do tej pory opierała się głównie na protokole HTTP, który jest mechanizmem typu pull (klient wysyła request i otrzymuje odpowiedź od serwera). Serwis typu push działa tak, że otwiera połączenia od klientów i notyfikuje ich o zmianach w jakimś źródle danych (np. w tabeli bazy danych). Podobnie działają mechanizmy typu publish - subscribe (np. MSMQ), ale potrzebujemy czegoś, co będzie dobrze działało na każdej platformie i każdym urządzeniu.

Programowanie w SignalR daje właśnie taki model ideowy zapewniając dobór technologii odpowiadającej możliwościom urządzenia klienckiego. Serwisy typu push są w SignalR zaimplementowane na cztery sposoby, rozpoczynając od tych najmniej wydajnych, a kończąc na najwydajniejszych:

  1. Long polling - mechanizm cyklicznego odpytywania serwera AJAX-owymi zapytaniami. Zapytanie takie ma ustawiony długi timeout (np. 30 sekund), a serwer nie odpowiada na nie od razu, ale w momencie, gdy pojawią mu się jakieś dane do wysłania. Jeżeli serwer nie ma nic ciekawego do wysłania, to nie wysyła odpowiedzi, a klient ponowi żądanie za 30 sekund
  2. Forever frame - po stronie klienta pojawia się ukryty iFrame, który wysyła zapytanie do serwera. Serwer zwraca odpowiedzi z nagłówkiem Transfer-encoding: chunked, który pozwala na wysłanie odpowiedzi w kilku paczkach. Każda taka wiadomość jest wysyłana tylko wtedy, kiedy na serwerze pojawią się nowe dane. Serwer wysyła wiadomości, które wstrzykują skrypt wywołujący jakąś metodę po stronie klienta.
  3.       
  4. Server-sent events - jednokierunkowy model komunikacji, w którym serwer wysyła do klienta zdarzenia. Wykorzystuje ideę persistent connection (reużywania połączenia TCP do wysłania wielu requestów / responsów w oparciu o nagłówek connection: 'keep-alive'). Wiadomości takie wykorzystują specjalny content-type: text/event-stream, a po stronie klienta także obiekt EventSource
  5. WebSocket - komunikacja dwukierunkowa, oparta na prostym API WebSocket ze specyfikacji HTML5. Przeglądarka negocjuje z serwerem upgrade protokołu z HTTP/HTTPS na odpowiednio WS lub WSS i jeżeli serwer wyrazi zgodę (kod HTTP 101), to połaczenie TCP/IP zostanie użyte do otwarcia dwukierunkowego kanału pomiędzy klientem, a serwerem. Po stronie JS mamy do dyspozycji obiekt WebSocket.
SignalR może być osadzony w aplikacji ASP.NET lub jako self-host. Pracę z tym frameworkiem najlepiej rozpocząć od dodania kilku NuGetów:



Następnie tworzymy najprostszy rodzaj huba - echo, które będzie odpowiadało na klienckie wiadomości.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WebApp.Start<WsStartup>("http://localhost:1968"))
            {
                Console.WriteLine("Server running!");
                Console.ReadLine();
            }
        }
    }

    public class WsStartup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.MapSignalR();
        }
    }

    [HubName("echo")]
    public class EchoHub : Hub
    {
        public string Call(string text)
        {
            return text + " from hub";
        }
    }
}

Wywołanie metody WebApp.Start("http://localhost:1968") powoduje zainicjalizowanie endpointów SignalR za pomocą klasy Startup pod wyspecyfikowanym adresem. Atrybut HubName określna przyjazną nazwę, po której będzie łączył się do niego klient. 

Najprostszy przykład kodu klienckiego (wysyłający wiadomość i wyświetlający odpowiedź) wygląda następująco:
 

<!DOCTYPE html>
<html >
<head>
    <title></title>
    <script src="Scripts/jquery-2.1.0.js"></script>
    <script src="Scripts/jquery.signalR-2.0.2.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
        $(function () {
            var hub = $.connection.echo;
            $.connection.hub
                .start()
                .done(function () {
                    hub.server.call('Hello SignalR!').done(function(msg){
                      alert(msg);
                    });;
                });
        });
    </script>
</head>
<body>
</body>
</html>

Trzeci tag <script> wskazuje na dynamiczny endpoint /signalr/hubs wystawiony przez serwer. Endpoint ten generuje w locie kod JS na podstawie dostępnych hubów. Dzięki niemu możemy pobrać referencję do naszego huba ($.connection.echo). Następnie w asynchroniczny sposób zostaje wołana metoda start. Metoda ta zwraca obiekt promise, w którym możemy zasubskrybować się na metodzie done, gdzie możemy wołać kod z naszego huba.

piątek, 22 lutego 2013

[HTML|JS|CSS] HTML5: WebSockets

Poprzedni post wprowadził do tematyki WebSocketów oraz pokazał, jak prosto zaimplementować je po stronie serwerowej. Tym razem czas na stronę kliencką, gdzie dzięki API HTML5 możemy w prosty sposób wysyłać i odbierać wiadomości. Kluczową funkcją konstruktora jest WebSocket, gdzie jako parametr podaje się URI serwera z gniazdem. Do dyspozycji mamy cztery zdarzenia, do których należy dopisać callbacki. Są to:

  • open
  • message
  • error
  • close
Do komunikacji z serwerem mamy funkcje send i close.

var close = document.getElementById("close");
var send = document.getElementById("send");

socket = new WebSocket("ws://localhost:9001", "echo-protocol");

socket.addEventListener("open", function(event) {
  status.textContent = "Connected";
});

socket.addEventListener("message", function(event) {
  var element = document.createElement('li');
  element.innerHTML = event.data;
  ul.appendChild(element); 
});

socket.addEventListener("error", function(event) {
  alert('Error');
});

socket.addEventListener("close", function(event) {
  status.textContent = "Not Connected";
});


close.addEventListener("click", function(event) {
  message.textContent = "";
  socket.close();
});

send.addEventListener("click", function(event) {
  socket.send(text);
  text.value = "";
});

[HTML|JS|CSS] Node.js: WebSockets

WebSockety to ciekawa technologia wykorzystywana w modelu klient - serwer. Zasada działania jest bardzo prosta. Pomiędzy przeglądarką a serwerem otwierany jest dwukierunkowy kanał komunikacji. Obie strony mogą wysyłać wiadomości bez konieczności odpytywania się nawzajem, a także przetwarzać otrzymane wiadomości na zasadzie obsługi zdarzeń. Zgodnie ze specyfikacją, adresy uri dla websocketów zaczynają się od ws lub wss (dla połączeń szyfrowanych).

Implementując WebSockety w Node.js, najwygodniej jest skorzystać z modułu ws. Obsługa połączenia a także wiadomości tradycyjnie wykonywana jest w callbackach, przy czym należy pamiętać że callback dla wiadomości zagnieżdża się w callbacku obsługi połączenia.

var ws = require('ws');
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: 9002});

wss.on('connection', function(ws) {
 ws.on('message', function(message) {  
  var date = new Date();
  var str = date.toLocaleDateString() + ' ' +
   date.toLocaleTimeString();

  var reversed = "";
  for (var i = message.length - 1; i >= 0; i--) {
   reversed += message[i];
  }
   ws.send(reversed);
  });

 var date = new Date();
 var str = date.toLocaleDateString() + ' ' +
  date.toLocaleTimeString();
 ws.send('WebSocket connected at: ' + str);
});