ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 148
Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 28
Abonament PDF

Websockets – http pe steroizi

Philip Peterhansl
IT Consultant Automotive
@.msg systems Romania



PROGRAMARE

Http a apărut în 1999, dar cererea în continuă creștere a aplicațiilor web moderne pentru servere push și un protocol de comunicare mai eficient a dus la definirea protocolului Websocket în 2011.

Întrebările puse la Conferința Java 2014 în Cluj au fost simptomatice pentru noile tehnologii:

Acest articol promovează Websockets și descrie în linii generale cum să le folosești și motivele pentru care ar trebui să le folosești.

Securitatea Websocket este un subiect important, dar nu poate fi acoperit în acest articol. Vedeți Linkuri utile pentru mai multe informații.

Cum se folosesc Websockets?

Implementările Websocket partajează o definiție de interfață comună între server, client și chiar între limbajele de programare. Următoarele exemple de cod vor implementa un exemplu elementar de dialog prin conectarea unui client Java și unul Javascript la un server Java.

Utilizați următoarea funcție expert în proiectele voastre pentru server și client Java pentru a include API JSR-356 pentru Java Websockets:

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
</dependency>

Server Java: Adnotat ServerEndpoint

Mai întâi creăm serverul utilizând ServerEndpoint adnotat, definit în JSR-356. Acolo mai există și o specificație pentru crearea programatică a punctului final (endpoint), dar nu ne vom ocupa de aceasta în acest articol.

Mai întâi codul, apoi explicațiile mai jos:

@ServerEndpoint(value = "/service")
public class ChatServerEndpoint {

    private static final Set connections =
            new CopyOnWriteArraySet<>();

    private Session session;

    @OnOpen
    public void start(Session session) {
        this.session = session;
        connections.add(this);
    }

}

Proprietatea valoare a ServerEndpoint definește calea pe care acest endpoint o receptează. URL-ul pentru conectarea la acest endpoint este: ws://://.

Adnotația @OnOpen marchează metoda start care va fi apelată atunci când se conectează un client. Ar trebui să faceți toată inițializarea care este necesară. În exemplul dialogului, sesiunea clientului conectat este memorată în setul de conexiuni, pentru utilizare ulterioară în interiorul metodei de difuzare.

Ce se întâmplă dacă un client se deconectează? Definiți o metodă, adnotați-o cu adnotația @OnClose și aceasta va fi apelată ori de câte ori un client se deconectează, indiferent de cauză:

@OnClose
public void end() {
    connections.remove(this);
}

În acest exemplu simplu de dialog, clientul deconectat este înlăturat din setul de conexiuni.

Nucleul oricărei aplicații antrenate de date, care implementează Websockets, este trimiterea și primirea de date. Soluția cea mai elementară pentru primirea de mesaje într-un JSR Endpoint este adnotarea unei metode cu @OnMessage și următoarea semnătură:

@OnMessage
public void incoming(String message) {
    broadcast(message);
}

Există mai multe moduri sofisticate de a primi (și a trimite) mesaje utilizând codoare și decodoare cu mesaje text și binare, dar nu ne vom ocupa de ele în acest articol. Căutați în API JSR-356 mai multe informații.

Trimiterea de mesaje se face prin sesiunea clientului care primește. Metoda broadcast trece prin fiecare client conectat din setul de conexiuni și trimite mesajul utilizând BasicRemote:

private static void broadcast(String msg) {
    for (ChatAnnotation client : connections) {
        try {
            synchronized (client) {
                client.session.getBasicRemote().sendText(msg);
            }
        } catch (IOException e) {
            connections.remove(client);
            try {
                client.session.close();
            } catch (IOException e1) {
                // Ignore
            }
        }
    }
}

BasicRemote obținut prin metoda getBasicRemote() din sesiunea clientului trimite mesajul în modul blocare. Există o implementare non-blocare, numită AsyncRemote. Aceasta este obținută prin folosirea metodei getAsyncRemote() a sesiunii clientului.

Acum avem un server care poate primi mesaje de la orice client și le poate trimite mai departe către toți clienții conectați. Haideți să ne uităm la implementarea clientului Java.

Client Java

Pentru crearea unui client Websocket în Java, un ClientEndpoint trebuie să fie definit într-un mod similar cu ServerEndpoint:

@ClientEndpoint
public class RemoteWebsocketClient {

    private Session session;

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
    }

    @OnMessage
    public void onMessage(String message) {
        System.out.println(message);
        //TODO: output message in a chat window
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {

    }

}

În acest exemplu simplu de dialog, noi trebuie doar să implementăm metoda adnotată @OnMessage. Metoda numai indică mesajul primit pe consolă.

Veți avea nevoie de o implementare JSR-356 pe partea client, deoarece nu există nicio implementare cuprinsă în Java JRE. Implementarea standard este Project Tyrus și este utilizată în acest exemplu.

Adăugați următoarele funcții la POM al proiectului client al vostru pentru a utiliza Tyrus în modul autonom:

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-server</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-client</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-container-grizzly</artifactId>
    <version>1.0</version>
</dependency>

Să conectăm clientul la server. Este foarte ușor, prin apelarea metodei connectToServer din ClientManager. Vezi sursa completă pentru ChatClient:

public class ChatClient {

    private ClientManager manager;

    public void connect(URI uri) {
        this.manager = ClientManager.createClient();
        try {
            manager.connectToServer(ChatClientEndpoint.class, uri);
        } catch (DeploymentException | IOException e) {
            System.exit(-1);
        }
    }

    public void run() {
        String msg = System.in.readLine();
        while (!"".equals(msg)) {
            manager.getSession().getBasicRemote().send(msg);
            msg = System.readLine();
        }
    }

    public void main(String[] args) {
        ChatClient cc = new ChatClient();
        cc.connect(URI.create("ws://localhost:8080/chat/service"));
        cc.run();
    }
}

Clientul de dialog se conectează la server prin apelarea connectToServer, furnizând o clasă de implementare ClientEndpoint și un URL la care să te conectezi. Bucla principală așteaptă ca input-ul de la utilizator să fie trimis clientului. Operarea mesajelor este realizată de către ChatClientEndpoint.

Javascript

Codul pentru un client Websocket Javascript este aproape identic cu Java ClientEndpoint. Conexiunea este realizată într-un mod specific browser-ului, căci Mozilla Firefox are o implementare individuală numită MozWebsocket în loc de Websocket standard:

var connect = function(url) {
    if ('WebSocket' in window) {
        socket = new WebSocket(url);
    } else if ('MozWebSocket' in window) {
        socket = new MozWebSocket(url);
    } 
};

Operarea mesajelor are loc în interiorul metodei socket.onmessage, care ar trebui să fie suprareglată. Pentru afișarea mesajelor dialog, vom crea un nou paragraf și îl vom atașa unei părți div din pagina html afișată.

socket.onmessage = function(msg) {
    var log = document.getElementById('log');
    var p = document.createElement('p');

    p.style.wordWrap = 'break-word';
    p.innerHTML = msg.data;
    log.appendChild(p);
}

Trimiterea se realizează prin utilizarea metodei de trimitere din socket:

send: function(msg) {
    socket.send(msg);
}

De ce să utilizăm websockets?

Specificația Websocket abordează problemele întâlnite de aplicațiile web moderne care folosesc protocolul http.

Cu Websockets primești:

Dezavantaje

Principalul dezavantaj al specificației websocket este că nu este specificat nici un protocol de nivel al aplicației. Aici suntem provocați noi ca dezvoltatori, să preluăm inițiativa și să dezvoltăm niște protocoale de comunicare generice pentru aplicații, care să completeze această lipsă.

Cu un protocol generic al aplicației, putem aborda al doilea dezavantaj: protocolul websocket nu specifică un mecanism pentru garantarea livrării mesajelor – o cerință majoră în utilizarea comercială.

Deși nu sunt de nerezolvat, aceste două probleme sunt răspunzătoare pentru faptul că Websockets nu are amploarea pe care o merită.

Pe scurt

După părerea mea, Websockets are într-adevăr beneficii imense în comparație cu comunicarea http tradițională. De aceea, aștept cu nerăbdare să utilizez Websockets pentru un produs comercial în viitor.

Aș dori să compar Websockets cu XMLHttpRequest, înainte de a avea parte de o reclamă exagerată, ca parte din AJAX: de îndată ce XMLHttpRequest a devenit utilizabil cu biblioteci terțe părți ușor de utilizat și de încredere, a început Web 2.0.

Websockets mai necesită îmbunătățiri în ceea ce privește utilizarea mai facilă a bibliotecilor de asemenea, conducându-se astfel aplicațiile client-server comerciale la un nivel nou.

Suport platformă

Browsers

Mobile Browsers

Servers

Link-uri utile

Conferință TSM

NUMĂRUL 147 - Automotive

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects