Windows Consumer Preview의 WebSocket
Windows 8 Consumer Preview 및 Server Beta에서 IE10 및 기타 모든 Microsoft WebSocket 클라이언트와 서버 기능은 현재 IETF WebSocket Protocol 최종 버전을 지원합니다. 또한 IE10은 W3C WebSocket API 권장 기술 후보에 올라 있습니다.
WebSocket은 안정적입니다. 개발자는 WebSocket을 사용하여 혁신적인 응용 프로그램 및 서비스 개발을 바로 시작할 수 있습니다. 이 글에서는 W3C WebSocket API 및 기본 WebSocket 프로토콜에 대해 간략하게 소개하겠습니다. 업데이트된 Flipbook 데모는 최신 버전의 API 및 프로토콜을 사용합니다.
저는 이전 글에서 다음과 같은 WebSocket 시나리오를 소개했습니다.
WebSocket을 사용하면 웹 응용 프로그램이 브라우저에서 실시간으로 알림 및 업데이트를 제공할 수 있습니다. 개발자는 실시간 시나리오를 지원하지 않는 브라우저의 원본 HTTP 요청-응답 모델에서 작업을 해야 하는 문제에 직면해 있습니다. WebSocket을 사용하면 브라우저가 서비스를 이용하여 양방향 전이중 통신 채널을 열 수 있습니다. 그러면 각 방향에서 이 채널을 사용하여 반대 방향으로 즉시 데이터를 보낼 수 있습니다. 이제 소셜 네트워킹 및 게임 사이트에서 금융 사이트에 이르기까지 다양한 브라우저에서 동일한 마크업을 사용하여 보다 원활하게 실시간 시나리오를 제공할 수 있습니다.
2011년 9월에 글을 작성한 이후 작업 그룹은 상당한 성과를 거두었습니다. WebSocket 프로토콜은 이제 IETF 제안 표준 프로토콜입니다. 또한 W3C WebSocket API는 W3C 권장 기술 후보에 올라 있습니다.
에코 서버 사용 사례로 본 WebSocket API
아래 코드 조각은 ASP.NET의 System.Web.WebSockets namespace로 만든 간단한 에코 서버를 사용하여 응용 프로그램에서 보낸 텍스트 및 이진 메시지를 반향합니다. 사용자는 응용 프로그램을 사용하여 텍스트 메시지로 반향될 텍스트를 입력하거나 이진 메시지로 반향될 그림을 그릴 수 있습니다.
WebSocket과 HTTP 폴링 간의 대기 시간 및 성능 차이를 실험할 수 있는 정교한 예를 보려면 Flipbook 데모를 참조하시기 바랍니다.
WebSocket 서버 연결에 대한 세부 정보
다음은 응용 프로그램과 서버 간의 직접 연결을 기반으로 한 간략한 설명입니다. 프록시가 구성되면 IE10은 프록시에 HTTP CONNECT 요청을 보내 프로세스를 시작합니다.
WebSocket 개체가 생성되면 클라이언트와 서버 간에 핸드셰이크가 교환되고 WebSocket 연결이 설정됩니다.
IE10이 서버에 HTTP 요청을 보내 프로세스를 시작합니다.
GET /echo HTTP/1.1
Host: example.microsoft.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://microsoft.com
Sec-WebSocket-Version: 13
이 요청의 각 부분을 살펴보겠습니다.
방화벽, 프록시 및 기타 매개를 트래버스할 수 있는 표준 HTTP GET 요청을 사용하여 연결 프로세스가 시작됩니다.
GET /echo HTTP/1.1
Host: example.microsoft.com
HTTP Upgrade 헤더가 서버에 응용 프로그램-계층 프로토콜을 HTTP에서 WebSocket 프로토콜로 전환하라고 요청합니다.
Upgrade: websocket
Connection: Upgrade
그러면 서버가 요청에 응답하여 WebSocket 프로토콜을 이해한다는 것을 알리기 위해 Sec-WebSocket-Key 헤더의 값을 변경합니다.
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
IE10는 Origin 헤더를 설정하여 서버가 원본 기반 보안을 적용하도록 허용합니다.
Origin: http://microsoft.com
Sec-WebSocket-Version 헤더는 요청 받은 프로토콜 버전을 식별합니다. 버전 13은 IETF 제안 표준의 최종 버전입니다.
Sec-WebSocket-Version: 13
서버가 응용 프로그램-계층 프로토콜 요청을 수락하면 HTTP 101 전환 프로토콜 응답을 반환합니다.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
서버는 WebSocket 프로토콜을 이해한다는 것을 보여 주기 위해 클라이언트 요청의 Sec-WebSocket-Key에 표준 전환을 수행하고 Sec-WebSocket-Accept 헤더에 결과를 반환합니다.
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
그러면 IE10은 Sec-WebSocket-Key와 Sec-WebSocket-Accept를 비교하여 서버가 HTTP 서버가 아닌 WebSocket 서버인지 검사합니다.
클라이언트 핸드셰이크는 IE10과 서버 간에 HTTP-on-TCP 연결을 설정합니다. 서버가 101 응답을 반환한 후 응용 프로그램-계층 프로토콜은 HTTP에서 이전에 설정된 TCP 연결을 사용하는 WebSocket으로 전환됩니다.
이 시점에서 HTTP는 완전히 제외됩니다. 이제부터 가벼운 WebSocket 전신 프로토콜을 사용하여 양 끝점에서 아무 때나 메시지를 보내거나 받을 수 있습니다.
WebSocket 서버 연결 프로그래밍
WebSocket 프로토콜은 HTTP 방식과 비슷한 2개의 새로운 URI 방식을 정의합니다.
- "ws:" "//" host [ ":" port ] path [ "?" query ]는 “http:” 방식에서 모델링됩니다. 기본 포트는 80이며 보안되지 않은(암호화되지 않은) 연결에 사용됩니다.
- "wss:" "//" host [ ":" port ] path [ "?" query ]는 “https:” 방식에서 모델링됩니다. 기본 포트는 443이며 전송 계층 보안을 통해 터널링된 보안 연결에 사용됩니다.
프록시 또는 네트워크 매개가 있으면 보안 연결이 성공할 확률이 높습니다. 매개는 보안 트래픽을 변환하려고 시도할 가능성이 낮기 때문입니다.
다음은 WebSocket 연결을 설정하는 코드 조각입니다.
var host = "ws://example.microsoft.com";
var socket = new WebSocket(host);
ReadyState – Ready … Set … Go …
WebSocket.readyState 속성은 CONNECTING, OPEN, CLOSING 또는 CLOSED 등의 연결 상태를 나타냅니다. WebSocket이 처음 생성되면 readyState는 CONNECTING입니다. 연결이 설정되면 readyState는 OPEN으로 설정됩니다. 연결 설정에 실패하면 readyState는 CLOSED로 설정됩니다.
열기 이벤트 등록
연결이 생성될 때 알림을 받으려면 열기 이벤트를 등록해야 합니다.
socket.onopen = function (openEvent) {
document.getElementById("serverStatus").innerHTML = 'Web Socket State::' + 'OPEN';
};
메시지 발신 및 수신에 대한 세부 정보
핸드셰이크가 성공하면 응용 프로그램과 Websocket 서버가 WebSocket 메시지를 교환할 수 있습니다. 메시지는 하나 이상의 메시지 조각 또는 데이터 “프레임”으로 구성됩니다.
각 프레임은 다음과 같은 정보를 포함합니다.
- 프레임 길이
- 메시지의 첫 프레임에 메시지 유형(이진 또는 텍스트) 정보 포함
- 메시지의 마지막 프레임 여부를 나타내는 플래그(FIN)
IE10은 프레임을 하나의 완전한 메시지로 조합하여 스크립트로 전달합니다.
메시지 발신 및 수신 프로그래밍
API를 사용하면 send
응용 프로그램이 Websocket 서버에 메시지를 UTF-8 텍스트, ArrayBuffers 또는 Blob로 보낼 수 있습니다.
예를 들어 아래 코드 조각은 사용자가 입력한 텍스트를 검색하여 서버에 UTF-8 텍스트 메시지로 보내 반향되도록 합니다. 서버에서는 Websocket의 readyState가 OPEN인지 확인합니다.
function sendTextMessage() {
if (socket.readyState != WebSocket.OPEN)
return;
var e = document.getElementById("textmessage");
socket.send(e.value);
}
아래 코드 조각은 사용자가 캔버스에 그린 이미지를 검색하여 서버에 이진 메시지로 보냅니다.
function sendBinaryMessage() {
if (socket.readyState != WebSocket.OPEN)
return;
var sourceCanvas = document.getElementById('source');
// msToBlob returns a blob object from a canvas image or drawing
socket.send(sourceCanvas.msToBlob());
// ...
}
메시지 이벤트 등록
메시지를 받으려면 응용 프로그램에 메시지 이벤트를 등록해야 합니다. 이벤트 처리기는 MessageEvent.data에 데이터가 포함된 MessageEvent를 받습니다. 받는 데이터는 텍스트 또는 이진 메시지입니다.
이진 메시지를 받을 경우 WebSocket.binaryType 속성에 따라 메시지 데이터를 Blob으로 반환할 것인지 아니면 ArrayBuffer 데이터 형식으로 반환할 것인지가 결정됩니다. 이 속성을 “blob” 또는 “arraybuffer”로 설정할 수 있습니다.
아래 예제에서는 기본값인 “blob”을 사용합니다.
아래 코드 조각은 websocket 서버에서 반향된 이미지 또는 텍스트를 받습니다. 데이터가 Blob일 경우 이미지가 반환되어 대상 캔버스에 표시되고, 그렇지 않을 경우 UTF-8 텍스트 메시지가 반환되어 텍스트 필드에 표시됩니다.
socket.onmessage = function (messageEvent) {
if (messageEvent.data instanceof Blob) {
var destinationCanvas = document.getElementById('destination');
var destinationContext = destinationCanvas.getContext('2d');
var image = new Image();
image.onload = function () {
destinationContext.clearRect(0, 0, destinationCanvas.width, destinationCanvas.height);
destinationContext.drawImage(image, 0, 0);
}
image.src = URL.createObjectURL(messageEvent.data);
} else {
document.getElementById("textresponse").value = messageEvent.data;
}
};
WebSocket 연결 닫기에 대한 세부 정보
열기 핸드셰이크가 있으면 닫기 핸드셰이크도 있습니다. 각 끝점(응용 프로그램 또는 서버)에서 이러한 핸드셰이크를 시작할 수 있습니다.
특별한 종류의 프레임인 닫기 프레임을 다른 끝점으로 보냅니다. 닫기 프레임에는 상태 코드 및 연결을 닫는 이유가 포함될 수 있습니다. 프로토콜은 상태 코드의 적절한 값을 정의합니다. 닫기 프레임을 보낸 끝점은 닫기 프레임 후 더 이상 응용프로그램 데이터를 보내면 안 됩니다.
반대편 끝점이 닫기 프레임을 받으면 갖고 있는 닫기 프레임을 사용하여 받은 닫기 프레임에 응답합니다. 닫기 프레임에 응답하기 전에 보류 중 메시지를 보낼 수도 있습니다.
WebSocket 닫기 프로그래밍 및 닫기 이벤트 등록
응용 프로그램이 close
API를 사용하여 열린 연결에서 닫기 핸드셰이크를 시작합니다.
socket.close(1000, "normal close");
연결이 닫힐 때 알림을 받으려면 닫기 이벤트를 등록해야 합니다.
socket.onclose = function (closeEvent) {
document.getElementById("serverStatus").innerHTML = 'Web Socket State::' + 'CLOSED';
};
이때 close
API는 두 가지 매개 변수, 즉, 프로토콜 및 설명에 의해 정의된 상태 코드를 허용합니다. 상태 코드는 1000 또는 3000-4999 사이여야 합니다. 닫기가 실행되면 readyState 속성이 CLOSING으로 설정됩니다. IE10이 서버로부터 닫기 응답을 받으면 readyState 속성이 CLOSED로 설정되고 닫기 이벤트가 발생합니다.
Fiddler를 사용하여 WebSocket 트래픽 보기
Fiddler는 인기 있는 HTTP 디버깅 프록시입니다. 최신 버전의 경우 WebSocket 프로토콜을 일부 지원합니다. 아래 스크린샷과 같이 WebSocket 핸드셰이크에서 교환된 헤더를 검사할 수 있습니다.
또한 모든 WebSocket 메시지가 기록됩니다. 아래 스크린샷에서는 서버에 UTF-8 텍스트 메시지로 보낸 “spiral”이 반향된 것을 볼 수 있습니다.
결론
WebSocket에 대해 자세히 알고 싶은 분은 2011년 9월에 열린 Microsoft //Build/ 컨퍼런스의 다음 세션을 시청하시기 바랍니다.
Microsoft 기술로 WebSocket 서비스를 개발하는 데 관심이 있는 분들은 다음 글을 통해 많은 도움을 받을 수 있습니다.
지금 바로 WebSocket을 사용하여 개발을 시작하세요! 여러분의 많은 의견 바랍니다.
- Windows 네트워킹 수석 프로그램 관리자, Brian Raymor