brunch

You can make anything
by writing

C.S.Lewis

by zwoo Dec 05. 2020

카톡 1도 모자라 점점점(...) 기능이 나타났을 때

web socket 


나 지금 누구랑 얘기하냐?

카톡방에서 우리는 자주 집단적 독백을 한다. 각자 자기말만 하며 한참을 떠들어도 신기하게 대화는 이어진다. 자기가 원하는 화두를 하나씩 던지다 보면 물고기떼처럼 한 주제로 몰려들기 때문이다. 한참 뒤에 카톡을 확인한 누군가는 뒤늦게 그 주제에 대해 한마디 한다. 참여인원이 많은 카톡방에서는 이렇듯 대화의 흐름이 뒤죽박죽이다. 그러면 누군가 이렇게 말하곤 한다. 

"나 지금 누구랑 얘기하냐?"


대화  :  마주 대하여 이야기를 주고받음. 또는 그 이야기.


메신저앱이 주는 현장감이 물리적인 대화를 따라잡은 지금, 우리는 언제 어디서나 '대화'한다. 카톡에서 상대방이 읽었는지 안읽었는지 알 수 있는 숫자표시 기능은 놀라운 기능이었다. 그건 우리가 서로에게 좀더 집중할 수 있도록 만들어줬다. 하지만 숫자 1만 남겨두면 내가 메시지를 미리보기로라도 읽었는지 아니면 정말 바빠서 휴폰을 확인할 수 없었는지 상대방은 알 도리가 없으므로, 적어도 미뤄뒀다가 나중에 답장을 할 정도의 마음의 여유는 남아있었다. 그러나 페이스북 메신저를 시작으로 점점점(...) 기능이 만들어지면서 (어딘가에 더 먼저 이 기능을 만든 앱이 있을 수도 있다! 내게는 페북이 최초였다) 메시지의 실시간성이 한층 더 강화되었다. 타이핑하고 엔터를 침과 동시에 상대방이 지금 타이핑을 하고 있다는 '...' 말풍선이 뜨는 것을 보면 그 대화창에서 나가기란 쉽지 않았다. 넋놓고 집중하게 되었다. 아주 오래전에 문자메시지로만 대화하다가 처음 네이트온 채팅을 주고받기 시작했을 때처럼 모니터에 집중하며 기나긴 채팅을 이어갔다. 


'... 상대방이 입력중입니다 ... ' 


우리는 집단적 독백을 하지도, 나중에 답장을 하려고 한눈을 팔지도 않고 상대에게 온전히 집중했다. 마치 내 눈앞에 상대방이 앉아있는 듯이!


web socket

나는 말풍선 기능이 무척 놀라웠고, 아주 마음에 들었다. 누가 보낸 메시지가 내 메시지함에 들어와있는 건 숨쉬듯 당연했지만, 지금 대화하고 있는 상대가 타이핑 중인 것이 감지되어 내 눈앞에 애니메이션으로 나타나는 것은 혁신적으로 느껴졌다. 도대체 어떻게 이게 가능한 것인지 궁금했다. 최근 회사 내에서 개인 스터디를 발표할 기회가 있었고, 나는 말풍선 기능이 있는 채팅을 만들어보기로 했다. '자바스크립트 실시간 채팅' 을 검색하자 웹소켓, 소켓, 소켓io 라는 키워드가 박힌 자료들이 폭포처럼 쏟아졌다. 


웹소켓을 이해하려면 먼저 알아야할 키워드들이 있었다. 


- 네트워크의 7 계층

- HTTP 

- 패킷통신과 TCP/IP 규약


틈틈이 공부한다고 했는데도 이것들을 이해해서 글을 쓸 수 있게 되기까지 시간이 한달 정도 걸렸다. 그리고 아직도 틀린 부분이 있을 수 있어서 조금 걱정이 되기도 한다. 우선 내가 만든 채팅웹을 소개하고, 키워드들에 대해서는 내가 이해하고 있는 선에서 아래에서 간단히 설명해보도록 하겠다. 뭐 대단한 건 아니지만 이번 채팅웹은 만들면서도, 만들고 나서도 상당히 신기하고 뿌듯했다.


결론부터 말하자면 나는 웹소켓 기술을 직접 다루지는 않았고, socket io 라는 자바스크립트 라이브러리를 이용했다. express 노드 웹 프레임워크로 서버를 만들고, socket io 라이브러리를 서버쪽과 클라이언트에서 각각 임포트했다.뷰는 리액트로 그렸다. 또한 리액트 머티리얼 UI 의 인풋과 버튼이 예쁘길래 가져다 사용했다. (https://material-ui.com/)

Nacho Send 채팅화면
로컬 창 두개로 상호작용하는 모습



네트워크의 7 계층, 그중 4층에는 TCP/IP, 7층에는 HTTP 가 있다. 


네트워크는 두개 이상의 기기들이 서로 데이터를 교환할 수 있는 통신형태이다. 1980년대에 국제표준화기구에서 네트워크의 유지보수를 쉽게 하기 위해 단계를 7개의 독립적인 단계로 분리하고 표준규격모델로 정했다. 

이렇게 7단계로 표준화한 것을 OSI 7계층이라고 부른다. 1층은 비교적 단순한 전기신호를 송수신하는 물리적인 하드웨어 계층이고 위층으로 올라가면서 주소를 부여하고 경로를 설정하는 등의 단계를 거쳐 최종적으로 7번째 단계에서 우리에게 익숙한 HTTP, FTP 등등의 프로토콜에 의해 최종적으로 전송받은 패킷(데이터단위) 들을 처리해서 수신인이 확인할 수 있게 된다. 


최초의 통신방식은 1대1 회선을 통한 연결이었다. A와 B가 통신중이면 C가 A에게 급한 용무가 있어도 앞선 통신이 끊길 때까지 기다려야 했다. 이는 비효율적이었다. 이에 고안된 방식이 데이터를 조그마한 단위로 짤게 쪼개어 (패킷) 짧게 짧게 전송하는 방식이었다. 작게 쪼갠 패킷 단위의 데이터에 헤더를 붙여 이 데이터의 정보와 순서를 담아서, 수신하는 쪽에서 다시 순차적으로 이어붙인 데이터를 최종적으로 확인할 수 있도록 하는 방식이 TCP 방식이다. HTTP 와 웹소켓은 모두 이 TCP에 의존한다. 둘의 차이점은 바로 "실시간성"에 있다.


HTTP 방식으로는 1요청에 대한 1응답 방식으로 통신이 가능했다. 클라이언트가 서버에 보낸 요청은 일회적이며, 서버는 그 클라이언트를 기억할 수 없기 때문에 다음번 통신을 위해서는 다시 새로운 회선을 열어야 한다. 가령 업데이트된 내용을 보려면 새로고침을 하거나 라우트 이동을 해야했던 과거의 인터넷 통신 방식을 떠올릴 수 있다. 실시간성에 대한 요구가 커지면서 HTTP 의 여러가지 보완방식들이 등장했지만, 웹소켓방식은 근본적으로 사용자의 요청에 대한 응답만 가능했던 HTTP 의 통신규칙을 깨고 클라이언트와 서버의 TCP 연결이 계속 유지되도록 했다. 웹소켓은 HTTP 연결을 통해 시작하고, 핸드셰이킹과정을 거쳐 데이터 전송을 시작한다. 핸드셰이킹은 말 그대로 인사라고 해석할 수 있으며, 클라이언트와 서버가 서로 웹소켓 연결방식을 지원하는지 확인하는 과정이다. 이 과정이 없다면 한쪽에서 보낸 웹소켓 데이터를 다른 한쪽에서  HTTP 요청으로 받아들여 보안문제가 발생할 수 있다고 한다. 


한편, 나는 이쯤에서 보안에 관한 염려를 가질 수밖에 없었다. 


1. HTTP 요청을 통해 서버와 클라이언트가 연결된다.

2. 핸드셰이킹하여 웹소켓방식으로 바꾼다

3. 중요한 내용을 주고받는다.


이 세가지 방식이라면 누군가 메시지 내용을 엿보거나 가로챌 수 있겠다는 생각이 들었다. 웹소켓의 데이터 통신 방식이 여러 조각으로 나뉘어 짜여진 틀에 맞게 전송된다는 내용을 읽었지만 거기에도 보안에 관한 내용은 없었다. 그래서 좀더 찾아보다가 이 기술은 비교적 최신 기술이며 보안 방법이 완전히 고안되어 있지는 않다는 글을 보게 되었다. 다만 ws:// 로 시작하는 기존 스킴 대신 보안이 강화된 wss:// 를 사용하는 것을 권장한다고 적혀있었다. http 와 https 와의 관계와 유사하다. wss:// 를 사용하면 어지간한 공격에는 대응할 수 있다고 한다. 



socket io


내가 사용한 socket io 는 웹소켓을 활용하는, 엄밀히 말하면 웹소켓 프로토콜을 지원하는 브라우저에서는 웹소켓으로 통신하고 그렇지 않은 경우에는 클라이언트의 요청에 대한 연결을 최대한 유지시키는 HTTP long polling 방식으로 통신하도록 고안된 자바스크립트 라이브러리이다. 웹소켓과 api 도 거의 유사하게 생겼다. 


const express = require('express')         //express 프레임워크 사용
const http = require('http')                    
const app = express()
const server = http.createServer(app)
const socket = require('socket.io')        // socket io 라이브러리 사용
const io = socket(server)

io.on('connection', (socket) => {
  console.log(socket.id);

  socket.emit('your id', socket.id)
  socket.emit('test', 'this is a test')

  socket.on('send message', (body) => {
    io.emit('message', body)
  })

  socket.on('do broadcast', (body) => {
    console.log(body);
    socket.broadcast.emit('broadcast', body)
  })
}) 


서버쪽에서 이렇게 emit 과 broadcast.emit 메소드를 만들어둔 후, 클라이언트 쪽에서 메소드를 실행한다.


import io from 'socket.io-client'

const socketRef = useRef()

  socketRef.current = io.connect('/')

  socketRef.current.on('your id', (id) => {
    setYourId(id)
  })

  socketRef.current.on('message', (message) => {
    setMessages((oldMsgs) => [...oldMsgs, message])
  })

  socketRef.current.on('broadcast', (message) => {
    console.log(message);
    setBroadCastMessage(message.id + ' is typing...')
  })

...


<input onchange =()=>{
 const messageObject = {
    body: message,
    id: yourId, 
 }

socketRef.current.emit('do broadcast', messageObject)

}/>


...


<Button
onClick=()=>{
const messageObject = {
  body: message,
  id: yourId,
}
socketRef.current.emit('send message', messageObject)

}>
send </Button>


즉, input 에 타이핑 이벤트가 발생하면 나를 제외한 다른 유저들에게 '나'가 채팅중임을 알리고, send 버튼을 클릭하는 이벤트가 발생하면 나를 포함한 모든 유저들에게 해당 메시지를 보여준다. (자기가 보낸 메시지와 남이 보낸 메시지는 색으로 구분하도록 했다)


카톡 1과 말풍선 기능 자체는 서로 크게 다른 기능이 아니었다. 핵심은 실시간 연결에 있었던 것이다. 하지만 똑같이 실시간으로 연결되어있다고 해도, 사용자 입장에서 그 사실이 눈과 귀로 직접 느껴지는 것은 중요한 지점이라는 생각이 이번에 많이 들었다. 사용자는 우리가 말해주기 전까지 많은 기능들을 알지 못하고 있다. 자신이 얼마나 멋진 서비스를 사용하고 있는지, 어떤 것까지 할 수 있는지 알려줄 필요가 항상 있다! 









참고한 문서들 


RFC 6455 (웹소켓 규약 문서) : https://tools.ietf.org/html/rfc6455#section-7.1.7

OSI 모형 :  https://ko.wikipedia.org/wiki/OSI_%EB%AA%A8%ED%98%95 

TCP/IP : https://brunch.co.kr/@wangho/6

HTTP: https://ko.wikipedia.org/wiki/HTTP

패킷 : https://youngq.tistory.com/73

웹소켓 :https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%86%8C%EC%BC%93

HTTP 와 웹소켓 : https://medium.com/@chullino/http%EC%97%90%EC%84%9C%EB%B6%80%ED%84%B0-websocket%EA%B9%8C%EC%A7%80-94df91988788

how web socket works : https://sookocheff.com/post/networking/how-do-websockets-work/

websocket security : https://devcenter.heroku.com/articles/websocket-security




나초처럼 가볍게 채팅할 수 있는 나초센드 

https://github.com/newnorm/nacho-send

(호스팅은 연결하지 않았습니다. 아직은 로컬에서만 돌릴 수 있어요!)











이전 05화 웹스톰에서 단축키로 코드정리하기
brunch book
$magazine.title

현재 글은 이 브런치북에
소속되어 있습니다.

작품 선택

키워드 선택 0 / 3 0

댓글여부

afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari