Heim > Artikel > Web-Frontend > Praktischer Vortrag zu Web und WebSocket
Warum ist das Echtzeit-Web so wichtig? Wir leben in einer Echtzeitwelt, daher sollte der ultimative und natürlichste Zustand des Webs auch Echtzeit sein. Benutzer benötigen Echtzeitkommunikation, Daten und Suche. Auch unsere Anforderungen an Echtzeitinformationen im Internet werden immer höher. Wenn Informationen oder Nachrichten mit einer Verzögerung von mehreren Minuten aktualisiert werden, ist das einfach unerträglich. Mittlerweile haben viele große Unternehmen (wie Google, Facebook und Twitter) begonnen, dem Echtzeit-Web Aufmerksamkeit zu schenken und Echtzeitdienste anzubieten. Echtzeit-Web wird eines der heißesten Themen der Zukunft sein.
Die Entwicklungsgeschichte des Echtzeit-Webs
Das traditionelle Web basiert auf dem HTTP-Anfrage-/Antwortmodell: Der Client fordert eine neue Seite und der Server an Sendet den Inhalt an den Client. Der Client muss die Anfrage erneut senden, wenn er eine andere Seite anfordert. Später schlug jemand AJAX vor, das das Seitenerlebnis „dynamischer“ machte und im Hintergrund Anfragen an den Server initiieren konnte. Wenn der Server jedoch über mehr Daten verfügt, die an den Client übertragen werden müssen, ist es nicht möglich, die Daten nach dem Laden der Seite direkt vom Server an den Client zu senden. Echtzeitdaten können nicht an den Client „gepusht“ werden.
Um dieses Problem zu lösen, wurden viele Lösungen vorgeschlagen. Die einfachste (Brute-Force-)Lösung ist die Verwendung von Polling: Fordern Sie von Zeit zu Zeit neue Daten vom Server an. Dadurch wirkt die Anwendung für den Benutzer wie in Echtzeit. Tatsächlich führt dies zu Latenz- und Leistungsproblemen, da der Server jede Sekunde eine große Anzahl von Verbindungsanforderungen verarbeiten muss und jede Anforderung über einen TCP-Drei-Wege-Handshake und HTTP-Header-Informationen verfügt. Obwohl Polling auch heute noch in vielen Anwendungen eingesetzt wird, ist es nicht die idealste Lösung.
Später, mit der Einführung der Comet-Technologie, entstanden viele weitere fortschrittliche Lösungen. Zu diesen technischen Lösungen gehören Permanent Frame (Forever Frame), XHR Stream (XHR-Multipart), HTMLFile und Long Polling. Langes Polling bedeutet, dass der Client eine XHR-Verbindung zum Server initiiert. Diese Verbindung wird nie geschlossen und die Verbindung wird für den Client immer unterbrochen. Wenn der Server über neue Daten verfügt, sendet er umgehend eine Antwort an den Client und schließt dann die Verbindung. Anschließend wird der gesamte Vorgang wiederholt und auf diese Weise ein „Server-Push“ erreicht.
Comet-Technologie ist eine nicht standardmäßige Hack-Technologie. Aus diesem Grund wird die Browserkompatibilität zu einem Problem. Erstens kann das Leistungsproblem nicht gelöst werden. Jede zum Server initiierte Verbindung enthält vollständige HTTP-Header-Informationen, was ein heikles Problem darstellt, wenn Ihre Anwendung eine sehr geringe Latenz erfordert. Natürlich ist es nicht so, dass mit Comet selbst etwas nicht stimmt, denn Comet ist unsere einzige Wahl, bis es andere Alternativen gibt.
Browser-Plugins (z. B. Flash) und Java werden ebenfalls verwendet, um Server-Push zu implementieren. Sie können Socket-Verbindungen direkt mit dem Server auf Basis von TCP herstellen, was sich sehr gut zum Übertragen von Echtzeitdaten an den Client eignet. Das Problem besteht darin, dass diese Plug-ins nicht in allen Browsern installiert sind und sie insbesondere in Unternehmensnetzwerken häufig von Firewalls blockiert werden.
Jetzt hat die HTML5-Spezifikation eine Alternative für uns vorbereitet. Diese Spezifikation ist jedoch ihrer Zeit etwas voraus, insbesondere der IE. Da die meisten Browser HTML5 WebSocket noch nicht implementiert haben, ist dies immer noch die beste Lösung Benutze Comet.
WebSocket früher und heute
Wie wir alle wissen, besteht der Interaktionsprozess von Webanwendungen normalerweise darin, dass der Client eine Anfrage über den Browser sendet, der Server die Anfrage empfängt, sie verarbeitet und zurückgibt Das Ergebnis wird an den Client gesendet und der Client durchsucht. Dieser Mechanismus ist für Anwendungen akzeptabel, bei denen sich die Informationen nicht besonders häufig ändern. Für Anwendungen mit hohen Echtzeitanforderungen und massiver Parallelität ist er jedoch unzureichend, insbesondere angesichts des aktuellen boomenden Entwicklungstrends des mobilen Internets In der Branche ist eine hohe Parallelität eng mit Benutzern verbunden. Echtzeitreaktionen sind häufig ein Problem, mit dem Webanwendungen konfrontiert sind, z. B. Echtzeitinformationen zu Finanztiteln, geografische Standorterfassung in Webnavigationsanwendungen und Echtzeit-Nachrichtenübermittlung in sozialen Netzwerken , usw.
Traditionelles Anfrage-Antwort-Modell Die Webentwicklung verwendet normalerweise Echtzeit-Kommunikationslösungen, wenn es um solche Geschäftsszenarien geht. Die häufigsten sind:
Das Prinzip ist einfach und leicht zu verstehen. Das heißt, der Client hält die Datensynchronisation zwischen dem Client und dem Server aufrecht, indem er in bestimmten Abständen Anfragen in Form häufiger Anfragen an den Server sendet. Das Problem liegt auf der Hand: Wenn der Client mit einer festen Häufigkeit Anfragen an den Server sendet, werden die Daten auf dem Server möglicherweise nicht aktualisiert, was zu vielen unnötigen Anfragen, einer Verschwendung von Bandbreite und einer geringen Effizienz führt.
Basierend auf Flash implementiert Adobe Flash den Datenaustausch über seinen eigenen Socket und verwendet dann Flash, um entsprechende Schnittstellen für JavaScript-Aufrufe verfügbar zu machen, um eine Echtzeitübertragung zu erreichen. Diese Methode ist effizienter als Polling und bietet aufgrund der hohen Installationsrate von Flash ein breites Anwendungsspektrum. Allerdings ist die Flash-Unterstützung auf mobilen Internetterminals nicht gut. Im IOS-System gibt es kein Flash. Obwohl es in Android Flash-Unterstützung gibt, ist der tatsächliche Nutzungseffekt nicht zufriedenstellend und die Anforderungen an die Hardwarekonfiguration des Mobilgeräts sind relativ hoch. Im Jahr 2012 gab Adobe offiziell bekannt, dass das System Android 4.1+ nicht mehr unterstützt wird, und kündigte damit den Tod von Flash auf mobilen Endgeräten an.
Wie aus dem oben Gesagten hervorgeht, stößt das traditionelle Webmodell bei hohen Parallelitäts- und Echtzeitanforderungen auf unüberwindbare Engpässe. Wir benötigen einen effizienten und energiesparenden Zwei-Wege-Kommunikationsmechanismus, um Echtzeit sicherzustellen. Zeitdatenübertragung. In diesem Zusammenhang entstand WebSocket, bekannt als Web TCP, basierend auf der HTML5-Spezifikation.
In den Anfängen bildete HTML5 keine einheitliche Spezifikation in der Branche. Verschiedene Browser- und Anwendungsserverhersteller hatten unterschiedliche ähnliche Implementierungen, wie z. B. IBMs MQTT, Comet Open Source Framework usw. Bis 2014 war es HTML5 Mit der Förderung und Zusammenarbeit von Giganten wie Google wurde der Staub schließlich von einem Entwurf in eine tatsächliche Standardspezifikation umgesetzt. Verschiedene Hersteller von Anwendungsservern und Browsern begannen nach und nach Das WebSocket-Protokoll wurde auch in JavaEE7 implementiert, sodass sowohl der Client als auch der Server WebSocket verwenden können. Alle sind vollständig, Leser können die HTML5-Spezifikation überprüfen und sich mit der neuen HTML-Protokollspezifikation und der WebSocket-Unterstützung vertraut machen.
WebSocket-Mechanismus
Das Folgende ist eine kurze Einführung in das Prinzip und den Betriebsmechanismus von WebSocket.
WebSocket ist ein neues Protokoll in HTML5. Es realisiert eine Vollduplex-Kommunikation zwischen dem Browser und dem Server, wodurch Serverressourcen und Bandbreite besser gespart werden können. Es basiert auf TCP und überträgt Daten wie HTTP über TCP.
WebSocket ist ein bidirektionales Kommunikationsprotokoll. Nach dem Herstellen einer Verbindung können der WebSocket-Server und der Browser/Client-Agent aktiv Daten aneinander senden oder empfangen, genau wie es Socket erfordert Ähnlich wie bei TCP werden Client und Server über einen Handshake verbunden und können erst dann miteinander kommunizieren, wenn die Verbindung erfolgreich ist.
Die Interaktion zwischen herkömmlichem HTTP-Client und -Server im Nicht-WebSocket-Modus ist in der folgenden Abbildung dargestellt:
Abbildung 1. Traditionelles HTTP-Request-Response-Client-Server-Interaktionsdiagramm
Die Interaktion zwischen Client und Server im WebSocket-Modus ist wie folgt:
Abbildung 2. WebSocket-Request-Response-Client-Server-Interaktionsdiagramm
Abb. Aus dem Vergleich geht hervor, dass WebSocket im Vergleich zum herkömmlichen HTTP-Modus, bei dem jede Anforderung/Antwort vom Client eine Verbindung mit dem Server herstellen muss, ein TCP-Kommunikationsmodus mit langen Verbindungen ist, ähnlich wie Socket Sobald die WebSocket-Verbindung hergestellt ist, werden die nachfolgenden Daten in Frame-Sequenz übertragen. Bevor der Client die WebSocket-Verbindung trennt oder der Server die Verbindung trennt, müssen Client und Server die Verbindungsanforderung nicht erneut initiieren. Bei massiver Parallelität und hoher Interaktionslast zwischen Client und Server wird der Verbrauch von Netzwerkbandbreitenressourcen erheblich gesenkt und es ergeben sich offensichtliche Leistungsvorteile. Darüber hinaus sendet und empfängt der Client Nachrichten in Echtzeit über dieselbe dauerhafte Verbindung. Der sexuelle Vorteil liegt auf der Hand.
Werfen wir einen Blick auf den Unterschied zwischen WebSocket-Kommunikation und herkömmlichem HTTP durch die interaktiven Nachrichten zwischen dem Client und dem Server:
Auf der Clientseite instanziiert New WebSocket ein neues WebSocket-Clientobjekt. Stellen Sie eine Verbindung zur WebSocket-URL des Servers her, ähnlich wie bei ws://yourdomain:port/path. Das WebSocket-Clientobjekt wird automatisch analysiert und als WebSocket-Anfrage erkannt, wodurch eine Verbindung zum Server-Port hergestellt und der Handshake-Prozess zwischen den beiden Parteien durchgeführt wird Das Format der vom Client gesendeten Daten ist ähnlich:
Liste 1.WebSocket-Client-Verbindungsnachricht
GET /webfin/websocket/ HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost:8080 Sec-WebSocket-Version: 13
Wie Sie sehen können, ähnelt die vom Client initiierte WebSocket-Verbindungsnachricht der herkömmlichen HTTP-Nachricht. Der Parameterwert „Upgrade: websocket“ gibt an, dass es sich um eine WebSocket-Typ-Anfrage handelt, und „Sec-WebSocket-“. Key“ wird vom WebSocket-Client gesendet. Ein Base64-codierter Chiffretext erfordert, dass der Server eine entsprechende verschlüsselte „Sec-WebSocket-Accept“-Antwort zurückgibt, andernfalls gibt der Client einen „Fehler beim WebSocket-Handshake“ aus und schließt die Verbindung.
Das vom Server nach Empfang der Nachricht zurückgegebene Datenformat ist ähnlich:
Listing 2. Antwortnachricht des WebSocket-Servers
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
"Sec-WebSocket-Accept" Das Der Wert wird vom Server mit demselben Schlüssel wie der Client berechnet und an den Client zurückgegeben. „HTTP/1.1 101 Switching-Protokolle“ bedeutet, dass der Server die Client-Verbindung des WebSocket-Protokolls akzeptiert Der WebSocket-Verbindungs-Handshake auf der Serverseite ist erfolgreich und die anschließende TCP-Kommunikation kann durchgeführt werden. Leser können auf den WebSocket-Protokollstapel verweisen, um detailliertere interaktive Datenformate zwischen dem WebSocket-Client und -Server zu erfahren.
In Bezug auf die Entwicklung ist die WebSocket-API ebenfalls sehr einfach. Wir müssen nur WebSocket instanziieren und eine Verbindung herstellen. Dann können der Server und der Client einander senden und antworten Im Analyseabschnitt unten finden Sie eine detaillierte WebSocket-API und Code-Implementierung.
WebSocket-Implementierung
Wie oben erwähnt, ist die Implementierung von WebSocket in zwei Teile unterteilt: den Client und den Server. Der Client (normalerweise ein Browser) stellt eine WebSocket-Verbindungsanforderung aus und der Server antwortet. Eine Aktion ähnlich dem TCP-Handshake, wodurch ein schneller HTTP-Verbindungskanal zwischen dem Browser-Client und dem WebSocket-Server entsteht. Durch die anschließende direkte Datenübertragung zwischen beiden entfällt die Notwendigkeit, eine Verbindung aufzubauen und zu antworten.
Im Folgenden finden Sie eine kurze Beschreibung der WebSocket-Server-API und der Client-API.
WebSocket-Server-API
WebSocket-Server wird grundsätzlich von verschiedenen Mainstream-Anwendungsserverherstellern unterstützt, die der JEE JSR356-Standardspezifikations-API entsprechen (Einzelheiten finden Sie in der JSR356-WebSocket-API-Spezifikation), von denen einige dies auch tun Unten aufgeführt: Gängige kommerzielle und Open-Source-Anwendungsserver unterstützen WebSocket-Server:
Tabelle 1. WebSocket-Serverunterstützung
Hersteller Anmerkungen
IBM WebSphere WebSphere 8.0 oder höher wird unterstützt, und Versionen vor 7.X unterstützen in Kombination mit MQTT ähnliche lange HTTP-Verbindungen
Oracle WebLogic WebLogic 12c wird unterstützt, 11g- und 10g-Versionen unterstützen ähnliches Dauerhafte HTTP-Verbindungen über HTTP-Veröffentlichung
Microsoft IIS IIS 7.0+-Unterstützung
Apache Tomcat Tomcat 7.0.5+-Unterstützung, 7.0.2X und 7.0.3X durch benutzerdefinierte API-Unterstützung
Jetty 7.0+ unterstützt
Im Folgenden verwenden wir den Server-Beispielcode der Tomcat7.0.5-Version, um die Implementierung des WebSocket-Servers zu veranschaulichen:
JSR356 WebSocket-Spezifikation Verwendung javax.websocket .* API, Sie können Verwenden Sie die Annotation @ServerEndpoint als gewöhnliches Java-Objekt (POJO) als Endpunkt des WebSocket-Servers. Das Codebeispiel lautet wie folgt:
Listing 3. WebSocket-Server-API-Beispiel
Code-Erklärung:@ServerEndpoint("/echo") public class EchoEndpoint { @OnOpen public void onOpen(Session session) throws IOException { //以下代码省略... } @OnMessage public String onMessage(String message) { //以下代码省略... } @Message(maxMessageSize=6) public void receiveMessage(String s) { //以下代码省略... } @OnError public void onError(Throwable t) { //以下代码省略... } @OnClose public void onClose(Session session, CloseReason reason) { //以下代码省略... } }
Der obige prägnante Code richtet einen WebSocket-Server ein. Der Annotation-Annotationsendpunkt von @ServerEndpoint("/echo") gibt an, dass der WebSocket-Server auf der ws://[Server-IP-Seite ausgeführt wird Domänenname]:[Server-Port]/websockets/echo Zugriffsendpunkt, der Client-Browser kann bereits lange HTTP-Verbindungen zur WebSocket-Client-API initiieren.
Mit ServerEndpoint annotierte Klassen müssen über einen öffentlichen, parameterlosen Konstruktor verfügen. Die mit @onMessage annotierte Java-Methode wird zum Empfangen eingehender WebSocket-Informationen verwendet. Diese Informationen können im Textformat oder im Binärformat vorliegen.
OnOpen 在这个端点一个新的连接建立时被调用。参数提供了连接的另一端的更多细节。Session 表明两个 WebSocket 端点对话连接的另一端,可以理解为类似 HTTPSession 的概念。
OnClose 在连接被终止时调用。参数 closeReason 可封装更多细节,如为什么一个 WebSocket 连接关闭。
更高级的定制如 @Message 注释,MaxMessageSize 属性可以被用来定义消息字节最大限制,在示例程序中,如果超过 6 个字节的信息被接收,就报告错误和连接关闭。
注意:早期不同应用服务器支持的 WebSocket 方式不尽相同,即使同一厂商,不同版本也有细微差别,如 Tomcat 服务器 7.0.5 以上的版本都是标准 JSR356 规范实现,而 7.0.2x/7.0.3X 的版本使用自定义 API (WebSocketServlet 和 StreamInbound, 前者是一个容器,用来初始化 WebSocket 环境;后者是用来具体处理 WebSocket 请求和响应,详见案例分析部分),且 Tomcat7.0.3x 与 7.0.2x 的 createWebSocketInbound 方法的定义不同,增加了一个 HttpServletRequest 参数,使得可以从 request 参数中获取更多 WebSocket 客户端的信息,如下代码所示:
清单 4.Tomcat7.0.3X 版本 WebSocket API
public class EchoServlet extends WebSocketServlet { @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { //以下代码省略.... return new MessageInbound() { //以下代码省略.... } protected void onBinaryMessage(ByteBuffer buffer) throws IOException { //以下代码省略... } protected void onTextMessage(CharBuffer buffer) throws IOException { getWsOutbound().writeTextMessage(buffer); //以下代码省略... } }; } }
因此选择 WebSocket 的 Server 端重点需要选择其版本,通常情况下,更新的版本对 WebSocket 的支持是标准 JSR 规范 API,但也要考虑开发易用性及老版本程序移植性等方面的问题,如下文所述的客户案例,就是因为客户要求统一应用服务器版本所以使用的 Tomcat 7.0.3X 版本的 WebSocketServlet 实现,而不是 JSR356 的 @ServerEndpoint 注释端点。
WebSocket 客户端 API
对于 WebSocket 客户端,主流的浏览器(包括 PC 和移动终端)现已都支持标准的 HTML5 的 WebSocket API,这意味着客户端的 WebSocket JavaScirpt 脚本具备良好的一致性和跨平台特性,以下列举了常见的浏览器厂商对 WebSocket 的支持情况:
表 2.WebSocket 客户端支持
浏览器 支持情况
Chrome Chrome version 4+支持
Firefox Firefox version 5+支持
IE IE version 10+支持
Safari IOS 5+支持
Android Brower Android 4.5+支持
客户端 WebSocket API 基本上已经在各个主流浏览器厂商中实现了统一,因此使用标准 HTML5 定义的 WebSocket 客户端的 JavaScript API 即可,当然也可以使用业界满足 WebSocket 标准规范的开源框架,如 Socket.io。
以下以一段代码示例说明 WebSocket 的客户端实现:
清单 5.WebSocket 客户端 API 示例
var ws = new WebSocket(“ws://echo.websocket.org”); ws.onopen = function(){ws.send(“Test!”); }; ws.onmessage = function(evt){console.log(evt.data);ws.close();}; ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; ws.onerror = function(evt){console.log(“WebSocketError!”);};
第一行代码是在申请一个 WebSocket 对象,参数是需要连接的服务器端的地址,同 HTTP 协议开头一样,WebSocket 协议的 URL 使用 ws://开头,另外安全的 WebSocket 协议使用 wss://开头。
第二行到第五行为 WebSocket 对象注册消息的处理函数,WebSocket 对象一共支持四个消息 onopen, onmessage, onclose 和 onerror,有了这 4 个事件,我们就可以很容易很轻松的驾驭 WebSocket。
Wenn der Browser und der WebSocketServer erfolgreich verbunden sind, wird die Onopen-Meldung ausgelöst. Wenn die Verbindung fehlschlägt, das Senden und Empfangen von Daten fehlschlägt oder ein Fehler in der Datenverarbeitung vorliegt, löst der Browser die Onerror-Meldung aus empfängt die vom WebSocketServer gesendeten Daten und löst die Onmessage-Nachricht aus. Der Parameter evt enthält die vom Server übertragenen Daten. Wenn der Browser die vom WebSocketServer gesendete Anforderung zum Schließen der Verbindung empfängt, wird die Onclose-Nachricht ausgelöst. Wir können sehen, dass alle Vorgänge durch asynchrone Rückrufe ausgelöst werden, wodurch die Benutzeroberfläche nicht blockiert wird, eine schnellere Reaktionszeit erreicht wird und ein besseres Benutzererlebnis geboten wird.