본문 바로가기
SSL, HTTP, Network Basics

Websocket Protocol 에 대해서 이해해 보자 # Stomp

by Developer88 2023. 5. 8.
반응형

오늘은 WebSocket 에 대해서 정리해 보려고 합니다.

이 글에서는,

저희가 항상 사용하고 있는 Http Protocol 과 어떻게 다른지를 보면서,

WebSocket 에 대해서 이해해 보도록 하겠습니다.

 

1. Websocket 과 Http와의 차이점

가장 먼저 Websocket Protocol 에 대해서 알아야 합니다.

너무 깊이 들어간다기 보다는 어떤 형식에서,

HTTP와 다른지 기본적인 흐름에 대해서 이해하면서 시작하는 것이 좋을 텐데요.

 

HTTP는,

클라이언트가 서버와 약속 된 방식으로 http요청을 하면, 서버는 그에 맞는 데이터를 보내주는 방식입니다.

즉, 요청을 하면 답변을 하는 방식인데요.

Request-Response가 반복됩니다.

접속이 유지되지 않은 상태를 의미합니다.

 

반면 WebSocket은,

클라이언트가 원한다고 할 때만 데이터를 주는 것이 아니라,

한번 접속이 된 이후에 유지가 되기 때문에,

요청하지 않아도 서버에서 계속해서 데이터를 보낼 수 있는 방식입니다.

 

이런 Protocol은 언제 필요할까요?

예를 들어 생각해보면,

초단위로 주가가 실시간으로 변경되는 사이트들 보시면,

매번 클라이언트가 요청한다고 생각하면 너무나 비효율적이겠지요.

여기서 WebSocket이 사용된다면,

초반에 접속을 허가받을 때만 클라이언트가 요청하고,

이후에는 서버가 지속적으로 보내주는 데이터를 받기만 하면 됩니다.

 

2. Websocket Protocol 

이제 WebSocket 이 어떻게 작동하는지 보려고 하는데요.

위에서 언급한 것처럼,

HTTP에서는 약속된 방식으로 서버에 요청을 보내고, 그에 맞는 데이터를 수신했는데요.

즉, Request-Response가 계속 반복되어졌는데요.

WebSocket 에서는 socket에 접속을 요청하고, 그것에 허락을 받고 나면,

계속 접속상태가 유지됩니다.

그러한 과정이 어떻게 작동하는지 보도록 하겠습니다.

 

가장 먼저 살펴볼 것이 socket에 접속을 요청하는 HandShaking 과정입니다.

 

2-1. HandShaking Request

클라이언트와 서버가 WebSocket 연결이 되기위해서는,

클라이언트가 최초에 Http 요청을 통해서 Socket 연결을 요청해야 하는데요.

이것을 Opening HandShaking 이라고 부릅니다.

 

아래는 WebSocket 에 대한 규약이 정리된 RFC 6455에 나온 샘플 헤더입니다.

헤더 중에 Upgrade 값이 있는데요.

이것은 Http 에서 WebSocket 으로 Protocol Upgrade 요청을 의미합니다.

즉, 서버에게 이 다음부터는 WebSocket 으로 연결하자는 의미입니다.

Connection에도 Upgrade를 명시해 주어야 합니다.

 

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

 

 

참고로 Sec-WebSocket-Key 는 서버에 클라이언트가 base64로 인코딩해서 보내주는 값인데요.

 

 

2-2. HandShaking Response

위에서와 같이 요청을 하면 WebSocket 서버에서 응답을 보내주는데요.

 

101 Switching Protocols 로 Status Code를 받게 되면,

WebSocket이 연결된 것을 의미합니다.

Http에서200OK와 비슷한 의미라고 생각할 수 있습니다.

 

서버에의 Response Header에 다음과 같은 내용들을 보내주는데요.

이 중 sec-WebSocket-Accept에는 위에서,

Sec-WebSocket-Key로 보내 준 값을 변경하여 Hash 값으로 보내 준 값으로 승인의 의미를 담게 됩니다.

클라이언트는 이 값을 보고 정상적인 승인을 확인하게 됩니다.

 

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

 

 

2-3. HandShake 완료 후

HandShake 과정이 완료되면, 프로토콜이 WebSocket으로 변경되구요.

사용하는 주소도, ws 혹은 wss를 사용해서,

서버와 클라이언트가 양방향 통신을 하게 되는데,

이 때 사용하는 단위가 message 입니다.

하나의 message는 하나 또는 여러개의 frame들로 구성되어 있는데요.

WebSocket에서 가장 작은 데이터의 단위는 frame 이라고 할 수 있습니다.

그래서 WebSocket 에서는 frame의 sequece들이 전송되어진다고 볼 수 있습니다.

 

 

 

Frame 은 아래 이미지와 같이 구성되어 있는데요.

중요한 부분 몇개만 보면,

FIN은 메세지의 마지막 부분임을 의미하구요.

OPCODE는 Payload data를 어떻게 해석할지를 정의합니다.

예를 들면 다음과 같습니다.

 

  • %x0: a continuation frame(계속되는 것을 의미)
  • %x1: a text frame(Text를 의미)
  • %x2: a binary frame
  • %x3-7: reserved for further non-control frames
  • %x8: a connection close(Websocket 커넥션이 Close 되어서 Close Handshake가 시작될 것임을 의미)
  • %x9: a ping
  • %xA: a pong
  • %xB-F: reserved for further control frames

 

 

2-4. Close Handshake

위에서 언급하였던, WebSocket Protocol의 가장 작은 데이터인, Frame에,

Close 를 담아서 보내면 됩니다.

이것을 클라이언트나 서버 어느 한쪽에서 보내고 받으면,

Close Handshke가 되고, 연결은 종료가 됩니다.

 

2. WebSocket 라이브러리

당연히 위의 Websocket을 구현을 편하게 해주는 라이브러리들이 언어별로 있는데요.

위에서 WebSocket에 대한 개념을 이해하였다면,

다음과 같은 라이브러리들이 존재하므로, 이들을 이용하는 방법만 알면 됩니다.

  • Javascript - Websocket, Socket.io(HTML5 이외에서도 웹소켓처럼 사용이 가능)
  • Android - OkHTTP
  • Python - websockets

 

3. Stomp

WebSocket을 이용하는 서비스들을 보면, 메시지로 Stomp라는 것을 같이 이용하는 경우를 볼 수 있습니다.

WebSocket은 Text와 Binary 로만 데이터를 주고 받을 수 있는데요.

조금이라도 복잡한 계층구조의 데이터를 주고 받으려고 텍스트로 전송한다는 것이 그리 효율적이지는 않습니다.

 

이 때 종종 사용되는 것이, Stomp 라는 Protocol 인데요.

Stomp는 Simple Text Oriented Messaging Protocol 의 약자인데요.

핵심이 Text로 되어 있다는 점 입니다.

즉, 텍스트와 바이너리로만 데이터를 주고 받는 웹소켓통신에 적합한 프로토콜 입니다.

 

 

 

텍스트로 데이터를 주고 받기 때문에,

escape 문자가 중요한데요.

아래 공식문서에 나온 것처럼, 

C언어 스타일의 literal escape를 지원합니다.

 

 

 

Stomp라이브러리들이 존재하기는 하지만,

텍스트로 되어 있기 때문에,

클라이언트에서는 이런 라이브러리들 없이도.

몇번의 text replace만 거치면,

데이터를 parsing 할수 있는 경우가 많습니다.

 

예를 들어, JSON String 데이터를 서버에서 Stomp 프로토콜을 이용해서 보내면 결국 아래와 같은 부분이 텍스트에 포함되어 있을 텐데요. 앞과 뒤에는 전송관련 메시지들이 추가로 붙을테고, 그런 부분들을 없애주고, 중요 데이터부분의 escape literal 만 제거해주면,

대부분 그대로 사용가능한 경우가 많습니다.

 

{\"username\": \"park\", \"message\": \"Hello, world!\"}

 

 

4. 팁 및 주의할 점

4-1. null character

아래 문자를 Null Character인데요.

어떤 서버에서는 메시지의 마지막임을 의미하기 위해서 사용되기도 합니다.

  • \u0000 : Null Character

이러한 문자를 전송할 때는,

escape 문자가 들어있다고 그대로 쓰면 않되구요.

언어마다 다르겠지만,

"\\u0000" 과 같이 "\"도 같이 escape 시켜주어야만 합니다.

 

728x90

댓글