회사에서 데모 프로젝트를 수행하는데 웹소켓을 사용해 통신을 할 예정이라고 해서 공부하기 시작했다. 예전에 분명 써본거 같은데 기억이 안난다.. 아마 프로젝트를 끝내고 나면 더 완벽하게 이해할 수 있을 것 같은데, 그건 또 추후에 포스팅해야겠다. 현 시점에서 생각해본다면 비디오 데이터를 보여줘야하고, 실시간으로 업데이트되는 영상들을 띄어줘야하기 때문에 웹소켓을 사용해 실시간 네트워킹이 필요하기 때문이라고 생각한다.
Socket이란?
웹소켓에 대해 알아보기 전에 socket이 뭔지에 대해서 궁금했다.
socket은 프로그램이 네트워크에서 데이터를 주고받을 수 있도록 네트워크 환경에 연결할 수 있게 만들어진 연결부다. 일반적으로 TCP/IP 프로토콜을 이용하고, TCP/IP 4계층에서 전송 계층 위에 놓인다.
Socket을 이용한 통신 프로그래밍을 Socket Programming이라고 하고, 이는 Client Socket과 Server Socket으로 구분된다.
통신 연결 요청을 보내는 Client Socket 흐름은 아래와 같다.
1. 아무 정보가 들어있지 않은 빈 껍데기 Socket을 생성한다.
2. IP 주소와 Port 번호로 연결하고 싶은 대상을 특정하여 연결을 요청한다.
3. 데이터를 송수신하게 되는데, 수신하는 API는 별도의 Thread에서 진행하게 된다.
4. 더 이상의 데이터 송수신이 필요없어지게 되면, 소켓을 닫는다.
통신 연결 요청을 받아들이는 Server Socket 흐름은 아래와 같다.
1. 아무 정보가 들어있지 않은 빈 껍데기 Socket을 생성한다.
2. 포트를 사용해 프로세스를 식별하기 때문에 Server Socket이 고유한 포트 번호를 만들 수 있도록 Socket과 Port 번호를 바인딩한다. 참고로 하나의 프로세스는 같은 포트를 가진 Socket을 여러개 열 수 있다. (client 연결 요청을 받아들을 준비가 완료된 상태)
3. client가 연결을 요청할 때까지 계속 대기하다가, 연결 요청이 오면 대기 상태를 종료하고 리턴한다. 아직 연결이 된 상태는 아니다. (listen)
4. client 연결을 받고 새로 생성된 Socket과 Client Socket을 매핑한다. (accept)
5. 데이터를 송수신하게 되고, 수신하는 API는 별도의 Thread에서 진행하게 된다.
6. 더 이상의 데이터 송수신이 필요없어지게 되면, 소켓을 닫는다.
WebSocket이란?
websocket을 사용하면 서버와 브라우저 간 연결을 유지한 상태로 데이터를 교환할 수 있다. 다시 말해, 서버와 브라우저 간 통신은 HTTP가 아닌 웹소켓 프로토콜을 사용해 진행한다. 이 때 데이터는 packet 형태로 전달되고, 전송은 커넥션 중단과 추가 HTTP 요청 없이 양방향으로 이루어진다.
이러한 특징 때문에 websocket은 주식 트레이딩 시스템, 채팅, 비디오 데이터 같이 데이터 교환이 지속적으로 이뤄져야하는 서비스에 적합하다.
참고로 패킷(packet)은 pack과 bucket를 합친 말로 컴퓨터 간에 데이터를 주고 받을 때 네트워크를 통해서 전송되는 데이터 조각입니다.
간단한 예시
웹소켓 커넥션을 만들려면 new WebSocket을 호출하면 된다. 이 때 ws라는 특수 프로토콜을 사용한다.
let socket = new WebSocket("ws://javascript.info");
참고로, wss://라는 프로토콜도 있는데, 항상 wss://를 사용해야 한다. 보안과 신뢰성 측면에서 ws보다 뛰어나기 때문이다.
ws를 사용하여 데이터를 전송하면 데이터가 암호화되지 않은 채로 전송되기 때문에 데이터가 그대로 노출되고, 아주 오래된 proxy서버는 웹소켓을 몰라서 이상한 헤더가 붙은 요청이 들어왔다고 판단하고 연결을 끊어버린다.
반면 wss://는 TSL(전송 계층 보안(Transport Layer Security))이라는 보안 계층을 통과해 전달되므로 송신자 측에서 데이터가 암호화되고, 복호화는 수신자 측에서 이뤄지게 된다. 따라서 데이터가 담긴 패킷이 암호화된 상태로 proxy 서버를 통과하므로 proxy 서버는 패킷 내부를 볼 수 없게 된다.
socket이 정상적으로 만들어지면 open => message => close 순으로 이벤트가 동작한다.
open은 커넥션이 제대로 만들어졌을 때, message는 데이터를 수신했을 때, close는 커넥션이 종료되었을 때 발생한다.
1. 웹소켓 핸드셰이크
브라우저와 서버의 연결을 시작하게 해주는 단계를 핸드셰이크라고 한다. 참고로 최초로 접속할 때 HTTP 프로토콜 위에서 핸드셰이크를 하기 때문에 HTTP Header를 사용한다.
1. new WebSocket(url)을 호출
2. 즉시 소켓 연결 시작
3. 커넥션이 유지되는 동안 브라우저는 헤더를 사용해서 서버에 웹소켓을 지원하는지 물어봄
4. 서버가 맞다는 응답을 하면,
5. HTTP 프로토콜 대신 서버와 브라우저간 웹소켓 프로토콜을 사용하여 통신
웹소켓 요청 헤더와 응답 헤더
요청 헤더
GET /chat // 반드시 GET 메서드를 사용해야 한다.
Host: javascript.info
Origin: https://javascript.info
Connection: Upgrade // 클라이언트 측에서 프로토콜을 바꾸고 싶다는 신호
Upgrade: websocket // 어떤걸로 바꾸고 싶은지
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
- Origin: 클라이언트 오리진, 웹소켓 객체는 기본적으로 cross-origin 요청을 지원한다.
- Sec-WebSocket-Key: 보안을 위해 브라우저에서 생성한 키로, 서버는 해당 키를 바탕으로 토큰을 생성하고, 브라우저에게 돌려준다.
응답 헤더
101 Switching Protocols // 서버가 프로토콜 전환을 승인하면 응답코드 101 반환
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g= // 요청에서의 Key 값을 계산한 값으로 신원 인증에 필요한 헤더
- Sec-WebSocket-Accept: 특별한 알고리즘을 사용해 만든 Sec-WebSocket-Key이다. 이 값을 보고 브라우저는 서버가 진짜 웹소켓 프로토콜을 지원하는지 확인한다.
정리하자면 웹소켓을 사용하겠다는 HTTP 요청을 하고 OK 승인을 받으면 통신 규약을 HTTP에서 웹소켓으로 upgrade 시키고, 소켓을 뚫어 해당 소켓으로 데이터를 주고받을 수 있게 하는 것이다.
Extensions(확장)와 Subprotocols(서브 프로토콜) 헤더
웹소켓 통신은 Sec-WebSocket-Extensions와 Sec-WebSocket-Protocol 헤더를 지원한다.
Sec-WebSocket-Extensions 헤더는 브라우저에 의해 자동 생성되고, 그 값엔 데이터 전송과 관련된 무언가나 웹소켓 프로토콜 기능 확장과 관련된 것들이 나열된다.
Sec-WebSocket-Protocol 헤더에서는 앞으로 사용하게 될 데이터 포맷을 확인할 수 있다. 이는 new WebSocket의 두 번째 매개변수에 값을 넣어서 설정할 수 있다.
2. 데이터 전송
웹소켓 통신은 frame이라 불리는 데이터 조각을 사용해 이루어진다. 프레임은 서버와 클라이언트 양측에서 모두 보낼 수 있다. 참고로 프레임 내 담긴 데이터 종류는 다양하지만 WebSocket.send() 메서드는 텍스트나 이진 데이터만 보낼 수 있기 때문에 브라우저 환경에서 개발자는 해당 데이터만 다룬다.
3. close 핸드셰이크
데이터 송수신이 완료되면, client와 server 모두 Connection을 종료하기 위한 Frame을 전송할 수 있다. Connection을 종료하고 싶은 쪽에서 Connection을 종료한다는 frame을 보내면, 상대쪽에서 응답으로 close frame을 전송한다.
참고자료
읽어보기 좋은 자료
'CS > 그 외' 카테고리의 다른 글
HLS(HTTP 라이브 스트리밍)와 m3u8 (0) | 2024.06.23 |
---|---|
OAuth 인증 과정 (0) | 2024.01.24 |
인증과 인가 (0) | 2024.01.23 |
[⭐️⭐️⭐️⭐️⭐️] 브라우저의 렌더링 원리 (0) | 2023.03.10 |
댓글