>  기사  >  웹 프론트엔드  >  웹과 WebSocket 실용 강연

웹과 WebSocket 실용 강연

伊谢尔伦
伊谢尔伦원래의
2017-01-23 14:22:181319검색

실시간 웹이 왜 그렇게 중요한가요? 우리는 실시간 세상에 살고 있으므로 웹의 궁극적이고 가장 자연스러운 상태도 실시간이어야 합니다. 사용자에게는 실시간 커뮤니케이션, 데이터 및 검색이 필요합니다. 인터넷상의 실시간 정보에 대한 요구 사항도 점점 더 높아지고 있습니다. 정보나 메시지가 몇 분 지연된 후 업데이트되면 참을 수 없습니다. 이제 많은 대기업(구글, 페이스북, 트위터 등)이 실시간 웹에 주목하고 실시간 서비스를 제공하기 시작했습니다. 실시간 웹은 앞으로 가장 뜨거운 화두 중 하나가 될 것입니다.

실시간 웹의 발전 역사

전통적인 웹은 HTTP 요청/응답 모델을 기반으로 합니다. 클라이언트는 새 페이지를 요청하고 서버는 콘텐츠를 클라이언트에 전송하면 클라이언트는 다른 페이지를 요청할 때 요청을 다시 보내야 합니다. 나중에 누군가가 페이지 경험을 더욱 "동적"으로 만들고 백그라운드에서 서버에 대한 요청을 시작할 수 있는 AJAX를 제안했습니다. 그러나 서버에 클라이언트에 푸시해야 할 데이터가 더 많은 경우 페이지가 로드된 후 서버에서 클라이언트로 데이터를 직접 보낼 수 없습니다. 실시간 데이터는 클라이언트에 "푸시"될 수 없습니다.
이 문제를 해결하기 위해 많은 솔루션이 제안되었습니다. 가장 간단한(무차별적인) 해결책은 폴링을 사용하는 것입니다. 즉, 가끔씩 서버에 새 데이터를 요청하는 것입니다. 이를 통해 사용자는 애플리케이션이 실시간으로 느껴지게 됩니다. 실제로 서버는 매초 많은 수의 연결 요청을 처리해야 하고 각 요청에는 TCP 3방향 핸드셰이크와 HTTP 헤더 정보가 있기 때문에 지연 시간과 성능 문제가 발생합니다. 폴링은 오늘날에도 여전히 많은 응용 프로그램에서 사용되고 있지만 가장 이상적인 솔루션은 아닙니다.
나중에 Comet 기술이 도입되면서 더 많은 고급 솔루션이 등장했습니다. 이러한 기술 솔루션에는 영구 프레임(영구 프레임), XHR 스트림(xhr-multipart), htmlfile 및 긴 폴링이 포함됩니다. 긴 폴링은 클라이언트가 서버에 대한 XHR 연결을 시작한다는 것을 의미합니다. 이 연결은 절대 닫히지 않으며 클라이언트에 대한 연결은 항상 일시 중단됩니다. 서버에 새로운 데이터가 있으면 즉시 클라이언트에 응답을 보낸 다음 연결을 닫습니다. 그런 다음 전체 프로세스가 반복되고 이러한 방식으로 "서버 푸시"가 달성됩니다.
Comet 기술은 비표준 해킹 기술이기 때문에 브라우저 호환성이 문제가 됩니다. 우선, 성능 문제는 해결될 수 없습니다. 서버에 시작된 모든 연결은 완전한 HTTP 헤더 정보를 전달합니다. 이는 애플리케이션이 매우 낮은 대기 시간을 요구하는 경우 까다로운 문제가 될 것입니다. 물론, Comet 자체에 문제가 있는 것은 아닙니다. 다른 대안이 있을 때까지 Comet이 우리의 유일한 선택이기 때문입니다.
브라우저 플러그인(Flash 등)과 Java도 서버 푸시를 구현하는 데 사용됩니다. TCP를 기반으로 서버와 직접 소켓 연결을 설정할 수 있으며 이는 실시간 데이터를 클라이언트에 푸시하는 데 매우 적합합니다. 문제는 모든 브라우저에 이러한 플러그인이 설치되어 있지 않으며 특히 기업 네트워크에서 방화벽에 의해 차단되는 경우가 많다는 것입니다.
이제 HTML5 사양이 우리를 위한 대안을 준비했습니다. 그러나 이 사양은 시대에 비해 약간 앞서 있습니다. 특히 IE에서는 아직 지원하지 않습니다. 대부분의 브라우저가 아직 HTML5 WebSocket을 구현하지 않았기 때문에 현재 가장 좋은 방법은 여전히 ​​​​이를 지원하는 것입니다. 혜성을 사용하세요.

WebSocket의 과거와 현재

우리 모두 알고 있듯이 웹 애플리케이션의 상호 작용 프로세스는 일반적으로 클라이언트가 브라우저를 통해 요청을 보내고, 서버가 요청을 받아 처리하고 결과를 반환하는 것입니다. 이 메커니즘은 정보 변경이 특별히 빈번하지 않은 애플리케이션에는 허용되지만, 실시간 요구 사항이 높고 동시성이 큰 애플리케이션에는 특히 부족합니다. 업계에서 모바일 인터넷의 급속한 발전 추세에 따라 높은 동시성은 사용자와 밀접한 관련이 있습니다. 실시간 응답은 금융 증권에 대한 실시간 정보, 웹 탐색 애플리케이션의 지리적 위치 획득, 실제 웹 애플리케이션이 자주 직면하는 문제입니다. -소셜 네트워크 등에서 시간 메시지 푸시

기존의 요청-응답 모델 웹 개발에서는 일반적으로 이러한 비즈니스 시나리오를 처리할 때 실시간 통신 솔루션을 사용합니다.

폴링 원리는 간단하고 이해하기 쉽습니다. 즉, 클라이언트는 일정한 간격으로 빈번한 요청 형태로 서버에 요청을 보내 클라이언트와 서버 간의 데이터 동기화를 유지합니다. 문제는 분명합니다. 클라이언트가 고정된 빈도로 서버에 요청을 보내면 서버의 데이터가 업데이트되지 않아 불필요한 요청이 많아지고 대역폭이 낭비되며 효율성이 낮아질 수 있습니다.

Flash를 기반으로 Adobe Flash는 자체 소켓을 통해 데이터 교환을 구현한 다음 Flash를 사용하여 JavaScript 호출에 해당 인터페이스를 노출하여 실시간 전송을 구현합니다. 이 방법은 폴링보다 효율적이고, 플래시의 설치율이 높기 때문에 활용 범위가 넓습니다. 그러나 모바일 인터넷 단말에서는 플래시 지원이 좋지 않습니다. IOS 시스템에는 플래시가 없습니다. Android에서는 플래시를 지원하지만 실제 사용 효과는 만족스럽지 않으며 모바일 장치의 하드웨어 구성 요구 사항이 상대적으로 높습니다. 2012년 Adobe는 공식적으로 Android 4.1+ 시스템을 더 이상 지원하지 않겠다고 발표하면서 모바일 단말기에서 Flash가 종료됨을 알렸습니다.

위에서 볼 수 있듯이 기존 웹 모델은 높은 동시성 및 실시간 요구 사항을 처리할 때 극복할 수 없는 병목 현상에 직면하게 됩니다. 시간 데이터 전송. 이러한 맥락에서 Web TCP로 알려진 WebSocket은 HTML5 사양을 기반으로 탄생했습니다.

초창기 HTML5는 업계에서 통일된 사양을 형성하지 못했습니다. 다양한 브라우저 및 애플리케이션 서버 제조업체는 IBM의 MQTT, Comet 오픈 소스 프레임워크 등 서로 다른 유사한 구현을 했습니다. 2014년까지 HTML5는 IBM, Microsoft가 채택하고 Google과 같은 거대 기업의 홍보와 협력으로 마침내 먼지가 쌓이고 초안에서 실제 표준 사양으로 공식적으로 구현되었습니다. 다양한 응용 프로그램 서버 및 브라우저 제조업체가 점차 통합되기 시작했습니다. WebSocket 프로토콜은 JavaEE7에서도 구현되어 클라이언트와 서버 WebSocket이 모두 완성되었으며 독자는 HTML5 사양을 확인하고 새로운 HTML 프로토콜 사양과 WebSocket 지원에 익숙해질 수 있습니다.

WebSocket 메커니즘

다음은 WebSocket의 원리와 동작 메커니즘을 간략하게 소개합니다.

WebSocket은 HTML5의 새로운 프로토콜입니다. 브라우저와 서버 간의 전이중 통신을 실현하여 서버 리소스와 대역폭을 더 효율적으로 절약하고 실시간 통신을 실현합니다. TCP를 기반으로 하며 HTTP처럼 TCP를 통해 데이터를 전송합니다. 그러나 HTTP와의 가장 큰 차이점은 다음과 같습니다.

WebSocket은 연결이 설정된 후 소켓이 요구하는 것처럼 WebSocket 서버와 브라우저/클라이언트 에이전트가 서로 적극적으로 데이터를 보내고 받을 수 있는 프로토콜입니다. TCP와 마찬가지로 클라이언트와 서버는 핸드셰이크를 통해 연결되며, 연결이 성공한 후에만 서로 통신할 수 있습니다.

WebSocket이 아닌 모드에서 기존 HTTP 클라이언트와 서버 간의 상호 작용은 아래 그림에 나와 있습니다.

그림 1. 기존 HTTP 요청 응답 클라이언트-서버 상호 작용 다이어그램

웹과 WebSocket 실용 강연WebSocket 모드를 사용하는 클라이언트와 서버 간의 상호 작용은 다음과 같습니다.

그림 2. WebSocket 요청 응답 클라이언트-서버 상호 작용 다이어그램

웹과 WebSocket 실용 강연그림에서 각 요청-응답을 위해 클라이언트가 서버와 연결을 설정해야 하는 기존 HTTP 모드와 비교하여 WebSocket은 Socket과 유사한 TCP 장기 연결 통신 모드임을 알 수 있습니다. . WebSocket 연결이 설정되면 후속 데이터가 프레임 순서로 전송됩니다. 클라이언트가 WebSocket 연결을 끊거나 서버의 연결을 끊기 전에 클라이언트와 서버가 연결 요청을 다시 시작할 필요가 없습니다. 클라이언트와 서버 간의 대규모 동시성 및 높은 상호 작용 부하의 경우 네트워크 대역폭 리소스 소비를 크게 절약하고 명백한 성능 이점을 제공합니다. 또한 클라이언트는 동일한 영구 연결에서 실시간으로 메시지를 보내고 받습니다. 성적 이점은 분명합니다.

클라이언트와 서버 간의 대화형 메시지를 통해 WebSocket 통신과 기존 HTTP의 차이점을 살펴보겠습니다.

클라이언트 측에서 새 WebSocket은 새 WebSocket 클라이언트 개체를 인스턴스화합니다. ws://yourdomain:port/path와 유사한 서버 WebSocket URL에 연결합니다. WebSocket 클라이언트 객체는 자동으로 구문 분석되어 WebSocket 요청으로 인식되어 서버 포트에 연결되고 두 당사자 간의 핸드셰이크 프로세스를 수행합니다. 클라이언트가 보내는 데이터 형식은

목록 1.WebSocket 클라이언트 연결 메시지

와 유사합니다.
GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: http://localhost:8080
Sec-WebSocket-Version: 13

클라이언트가 시작한 WebSocket 연결 메시지가 기존 HTTP 메시지와 유사하다는 것을 알 수 있습니다. "Upgrade: websocket" 매개변수 값은 이것이 "Sec-WebSocket-Key" 유형 요청임을 나타냅니다. WebSocket 클라이언트가 보낸 메시지. Base64로 인코딩된 암호 텍스트를 사용하려면 서버가 해당 암호화된 "Sec-WebSocket-Accept" 응답을 반환해야 합니다. 그렇지 않으면 클라이언트가 "WebSocket 핸드셰이크 중 오류" 오류를 발생시키고 연결을 닫습니다.

메시지 수신 후 서버가 반환하는 데이터 형식은 유사합니다.

목록 2. WebSocket 서버 응답 메시지

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

"Sec-WebSocket-Accept" 값 "HTTP/1.1 101 Switching Protocols"는 서버가 클라이언트와 동일한 키를 사용하여 계산한 후 클라이언트 서버가 WebSocket 프로토콜의 클라이언트 연결을 수락한다는 의미입니다. WebSocket 연결 핸드셰이크가 성공하고 후속 TCP 통신이 수행될 수 있습니다. 독자는 WebSocket 프로토콜 스택을 참조하여 WebSocket 클라이언트와 서버 간의 보다 자세한 대화형 데이터 형식을 알아볼 수 있습니다.

개발 측면에서도 WebSocket API는 매우 간단합니다. WebSocket을 인스턴스화하고 연결만 생성하면 WebSocket 구현에서 서버와 클라이언트가 서로 메시지를 보내고 응답할 수 있습니다. 아래 사례 분석 섹션에서 자세한 WebSocket API 및 코드 구현을 볼 수 있습니다.

WebSocket 구현

위에서 언급한 것처럼 WebSocket의 구현은 클라이언트와 서버의 두 부분으로 나누어집니다. 클라이언트(일반적으로 브라우저)는 WebSocket 연결 요청을 발행하고 서버는 다음과 같습니다. 구현 TCP 핸드셰이크와 유사한 작업으로, 브라우저 클라이언트와 WebSocket 서버 간에 길고 긴 HTTP 연결 고속 채널을 형성합니다. 둘 사이의 후속 직접 데이터 전송을 통해 연결을 시작하고 응답할 필요가 없습니다.

다음은 WebSocket 서버 API와 클라이언트 API에 대한 간략한 설명입니다.

WebSocket 서버 API

WebSocket 서버는 기본적으로 JEE JSR356 표준 사양 API(자세한 내용은 JSR356 WebSocket API 사양 참조)를 준수하는 다양한 주류 애플리케이션 서버 제조업체에서 지원되며, 그 중 일부는 다음과 같습니다. 아래 나열된 일반적인 상용 및 오픈 소스 응용 프로그램 서버 지원 WebSocket 서버:

표 1. WebSocket 서버 지원

제조업체 비고

IBM WebSphere WebSphere 8.0 이상이 지원되며 MQTT와 결합된 7.X 이전 버전은 유사한 HTTP 긴 연결을 지원합니다.

Oracle WebLogic WebLogic 12c가 지원되며 11g 및 10g 버전도 유사한 지원 HTTP 게시를 통한 HTTP 영구 연결

Microsoft IIS IIS 7.0+ 지원

Apache Tomcat Tomcat 7.0.5+ 지원, 사용자 정의 API 지원을 통한 7.0.2X 및 7.0.3X

Jetty 7.0+ 지원

다음은 WebSocket 서버 구현을 설명하기 위해 Tomcat7.0.5 버전의 서버 예제 코드를 사용합니다.

JSR356 WebSocket 사양 사용법 javax.websocket .* API를 사용할 수 있습니다. WebSocket 서버의 엔드포인트로 @ServerEndpoint 주석을 일반 Java 객체(POJO)로 사용합니다. 코드 예제는 다음과 같습니다.

목록 3. WebSocket 서버 API 예제

@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) {
 //以下代码省略...
 } 
 
 }

코드 설명 :

위의 간결한 코드는 WebSocket 서버를 설정합니다. @ServerEndpoint("/echo")의 주석 주석 끝점은 WebSocket 서버가 ws://[서버 IP 또는 도메인 이름]:[에서 실행됨을 나타냅니다. 서버 포트]/websockets/echo 액세스 엔드포인트를 사용하면 클라이언트 브라우저는 이미 WebSocket 클라이언트 API에 대한 HTTP 긴 연결을 시작할 수 있습니다.

ServerEndpoint로 주석이 달린 클래스에는 매개변수가 없는 공용 생성자가 있어야 합니다. @onMessage 주석이 달린 Java 메서드는 들어오는 WebSocket 정보를 수신하는 데 사용됩니다.

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。

브라우저와 WebSocketServer가 성공적으로 연결되면 onopen 메시지가 트리거됩니다. 연결이 실패하거나 데이터 전송 및 수신이 실패하거나 데이터 처리에 오류가 있는 경우 브라우저는 onerror 메시지를 트리거합니다. WebSocketServer가 보낸 데이터를 수신하면 onmessage 메시지가 트리거되고, evt 매개변수에는 서버가 전송한 데이터가 포함됩니다. 브라우저가 WebSocketServer가 보낸 연결 종료 요청을 받으면 onclose 메시지가 트리거됩니다. UI를 차단하지 않고 더 빠른 응답 시간을 달성하며 더 나은 사용자 경험을 제공하는 비동기 콜백을 사용하여 모든 작업이 트리거되는 것을 볼 수 있습니다.


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.