일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- JWT 만들어보기
- nodejs파일업로드
- 세션으로 로그인 구현
- JWT 하드코딩
- 라우터미들웨어 분리
- express.static
- useEffect clean up
- buffer.from
- JWT 로그인 기능 구현
- javascript기초
- useContext
- 비동기파일업로드
- 아이디 중복체크기능
- ws 라이브러리
- mysql wsl
- next 매개변수
- 라우트 매개변수
- express session
- 라우터 분리
- css기초
- cookie-parser 만들어보기
- 시퀄라이즈 기본설정
- 라우터와 미들웨어
- express router
- express실행
- node.js path
- 블록 만들기
- OAuth 카카오
- FormData()
- Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
- Today
- Total
즐코
web socket (웹소켓) - 실시간, 양방향 통신 본문
여태 http 통신만 배우다 보니 웹소켓이란 걸 인지하지 못했다.
늘 우리가 접하는 채팅, 경매, 주식 사이트, 구글docs 등 실시간으로 통신이 필요할 경우엔 이 웹소켓 프로토콜을 사용한다.
http 통신은 클라이언트가 요청을 해야만 서버가 응답을 준다. 요청 없이는 서버는 아무것도 응답해주지 않는다.
이 websocket 통신은 그렇지 않다. 양방향이 가능하다. 서버도 클라이언트의 요청없이 선톡이 가능하다.
완벽한 비유는 아니지만, 문자 == http / 전화 == websocket
즉, 웹 접속을 할 때만 http로 접속하고 그 이후의 통신은 WebSocket 프로토콜로 이루어진다.
이렇게 실시간/양방향 통신을 구현하는데 대표적으로 2가지 방법이 있다.
WebSocket : 내부 라이브러리 / explorer는 지원하지 않음 & 직접 구현하는 거라 살짝 어렵지만 customize하기 쉬움
socket.io : 외부 라이브러리 / 100% JS로 이루어져 있고 브라우저 종류에 상관없이 실시간 웹 구현하게 해줌
브라우저마다 다르게 행동한다. 웹소켓이 지원되면 기존 웹소켓방식으로 동작하고, 아니라면 일반 http를 이용해서 실시간 통신을 흉내낸다고 한다.
Polling -> Server Sent Event -> Web Socket 이런식으로 실시간 양방향 데이터 방식이 발전해온 듯 하다.
Polling (클라이언트가 주기적으로 서버에 요청보내서 업데이트 있는지 확인하는 방식)
SSE (클라이언트 요청없이 서버가 주체적으로 데이터를 전송, 대신 클라이언트는 데이터를 서버로 보낼수 X, like 라디오)
WS (이벤트 방식으로 동작, 한번의 연결만 하면 됨, http와 포트 공유도 가능)
웹소켓 구조도
코드로 구현해보자. 오늘은 socket.io가 아닌 webSocket 라이브러리를 썼다.
오늘 배운 중요한 사실 - 콜백함수가 등장하면 거의 반사적으로 함수를 만들어서 빼줘야 코드를 읽기 좋게 짤 수 있다.
파일은 크게 server.js (익스프레스 서버용) & socket.js (웹소켓용) & index.js (브라우저-클라이언트) 으로 나뉜다.
익스프레스 서버와 포트 공유, 연결을 위해 웹소켓 서버 socket.js 작업부터 시작
<socket.js>
npm install ws 해주고 모듈 가져오기
const wss = new WebSocket.Server({ server })
이때, wss 객체를 만들어주는 코드인 const wss = new WebSocket.Server({ server }) 의 server 부분에 다른 port를 넣으면
const wss = new WebSocket.Server( { port:3005 } )
익스프레스 서버와 포트를 공유하는 게 아니라, 웹소켓 port를 따로 써서 연결하겠다는 뜻이라고 한다.
<server.js>
socket.js에서 당겨온 webSocket 모듈을 익스프레스 서버와 연결한다.
<index.js>
이 때 클라이언트(브라우저)에서 웹소켓 연결 요청을 서버에게 보내줘야한다.
브라우저 내장 객체 - WebSocket을 사용할 거다.
인자로는 웹소켓 연결을 요청할 URI를 넣어준다.
이 때, 웹소켓은 http 프로토콜이 아닌 ws 프로토콜을 사용하니 이부분도 평소와 다르게 수정하여서 넣어야 한다.
const webSocket = new WebSocket('ws://localhost:3000')
이렇게 하면 웹소켓 서버로 클라이언트가 요청을 보낸거고 => 클라이언트-서버-웹소켓으로 연결/통신이 되면
그때서야, socket.js의 wss.on ('connection', connectCb) 의 connection 이벤트가 발동되는 거다.
<socket.js>
다시 socket.js로 돌아와서 , connection 이벤트 이후 콜백 함수는 아래와 같이 만들었다.
여기서 콜백함수에 인자로 들어가는 ws, req는 다음과 같다.
ws : 연결에 대한 정보가 다 들어가 있다. (연결된 브라우저의 정보)
req : 요청 헤더에 대한 내용이 들어간다.
연결된 사용자의 정보가 담긴 긴 객체를 sockets라는 배열을 전역으로 선언해주고 거기에 담아준다.
다른 창 or 브라우저가 연결을 할때마다 저 ws 객체들(연결 정보)이 sockets 배열안에 쌓일거다
이때, ws와의 변수명 중복을 피하기 위해 wsConnector라는 전역 변수를 만들어서 그 안에 ws를 할당해주자.
이 때, req.headers['x-forwarded-for' ] || req.connection.remoteAddress 로 클라이언트의 IP를 알아낼수가 있다.
출력해보면, 아래 ::1 이 뜨는데 이건 127.0.0.1 (localhost)를 뜻한다고 한다.
나중에 실제로 접속한 사용자들의 아이피 주소를 DB에 저장해서 ip log를 남길 수도 있겠다.
req.headers를 통쨰로 출력해보면 아래와 같이 요청 헤더가 뜬다.
위의 코드에선 ws라는 연결 정보안에 id값으로 sec-websocket-key라는 값을 넣어준 것이다.
이제 인지해야할 것은 기본적으로 서버건 클라이언트건 event로 on(듣기), send(말하기)를 가지고 있다는 사실이다.
즉, 양쪽 다 데이터를 보낼 수 있고, 받을 수 있다는 사실이다.
이때, 브라우저에서 WebSocket 현재 연결상태 (readyState)에 따라 다른 이벤트 리스너가 쓰인다.
- WebSocket이 open 되었을 때 (데이터를 주고 받을 준비가 되었을 때) : onopen
- close 이벤트를 받았을 때 호출되는 이벤트 리스너 : onclose
- message 이벤트를 받았을 때 (서버로부터 메시지가 도착했을 때) : onmessage
- error라는 이벤트를 받았을 때 (에러 발생 상황 시) : onerror
이런 시점들을 잡아서 필요한 코드를 짤 수가 있겠다.
<index.js>
클라이언트 -> 서버에게 보낼 때, webSocket.send로 보내준다.
(form에서 채팅 내용을 submit했을때, form에서 일어나는 이벤트 콜백함수 submitHandler)
<socket.js>
ws가 연결되고나서, 그 안에서 on (듣기) 함수가 실행된다.
웹소켓 서버 -> 클라이언트 (브라우저)에게 답장을 send해줌
브라우저에서 보낸 input 값을 보면 객체가 출력되고 그 안에 type,data,author가 들어있다.
아래 코드에선 사실 type이 하나밖에 없어서 굳이 switch문을 써줄 필욘 없었지만,
여러 type이 존재한다면 그거에 맞춰서 다른 데이터를 답장으로 보낼 수 있겠다.
<index.js>
서버로부터 메시지를 받았을 때, 받은 정보(event객체의 data)를 사용해서 DOM을 그려주는 코드
이 때 그 객체안의 author와 input에서 받은 userid가 같다면 내 글만 style이 적용 되어서 다른 브라우저의 채팅글과 구분 지어줄 수 있겠다.
<socket.js>
채팅창을 나가게 된다면 (브라우저 창을 닫을때) close 콜백함수를 아래와 같이 만들어줌
연결 정보를 담은 sockets 배열에 새로운 sockets를 할당해주는 것
즉, close 이벤트를 만든 wsConnector.id 와 sockets안의 접속 정보의 아이디(v.id) 중 일치하지 않는 거만 sockets 배열안에 남겨 놓는 거다. close를 한 wsConnector.id만 빼고 다시 sockets 배열에 담긴 형태이다.
'NodeJS' 카테고리의 다른 글
Oauth2.0 - 카카오 로그인 API 구현 (0) | 2022.03.17 |
---|---|
Nodejs에서 파일 업로드 구현 - multer 라이브러리 사용 (0) | 2022.03.17 |
경로 / 내부 라이브러리 path (0) | 2022.03.16 |
ajax (XHR/fetch/axios) 아이디 중복체크 살짝 구현해보기 (0) | 2022.03.07 |
JWT로 로그인 기능 구현해보기 (0) | 2022.03.06 |