현재 N:N을 webRTC 구현 중 제대로 작동하지 않는 부분이 있어 전체적인 이해를 높이고자 강의를 빠르게 훑는중이라 생략된 내용 다수 있음
socket io는 실시간, 양방향, event 통신을 제공하는 프레임워크다
websocket은 socketio가 이러한 기능을 제공하는 방법 중 하나다.
만약 브라우저가 websocket을 지원하지 않으면 socketio는 다른 방법을 사용한다
실시간 기능을 쉽게 만드는 여러 기능,코드를 제공함
(자동으로 재연결을 시도한다던가..)
서버에서
socketio를 require하거나 import 해서 이런식으로 서버를 만든다
브라우저에서
뷰페이저에 위 파일을 추가(socketio를 설치)해준다.
이렇게 하는 이유는 이전 포스트에서 websocket을 쓸 때는 브라우저에서 제공하는 websocket을 썼다. 하지만 socketio는 websocket 이상의 기능을 제공하고 그런것들은 자동제공하지 않는다. 따라서 이런 코드를 가져와서 사용하는 것이다.
websocket은 서버에서 socket 연결이 생기면 해당 socket을 배열에 넣어서 연결된 socket들을 관리했다. 하지만 socketio는 알아서 socket들을 추적하여 관리한다
body
header
h1 Coogle
main
div#welcome
form
input(placeholder="room name",required,type="text")
button Enter Room
//브라우저에 socket.io 설치하기
script(src="/socket.io/socket.io.js")
script(src="/public/js/clientServer.js")
참고로 존재하지 않는 방에 들어가면 그게 곧 방을 만드는 거고 1명만 있는 방이 되는것임
방을 만드는 것 - 방에 들어가는 것이 같다는 걸 알아야함
방 이름을 입력하기 위한 form을 만들었다.
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//브라우저에서 socketio 연결하기 위해서는 io() 만 해주면 된다.
//io 함수가 알아서 socketio를 돌리는 서버를 찾아서 연결할것임
const socket = io();
const welcome = document.getElementById(`welcome`);
const form = welcome.querySelector(`form`);
function handleRoomSubmit(event){
event.preventDefault();
const input = form.querySelector(`input`);
//socketio는 emit으로 원하는 어떤 이벤트든 정의할 수 있고 string 뿐만 아니라 js object도 보낼 수 있다.
socket.emit(`enter_room`,{payload : input.value});
input.value = ``;
}
//방 이름 입력에 대해 이벤트리스너 등록
form.addEventListener(`submit`,handleRoomSubmit);
브라우저에서
socket.emit으로 "room"이라는 이벤트를 등록할 수 있다.
내가 원하는 아무 이벤트나 만들 수 있다.
또한 websocket으로 채팅을 구현할 때를 생각해보면 websocket.send에는 두번째 인자로 string만 전달이 가능해서 JSON을 stringify로 변환해서 보내는 등의 과정을 거쳤었다. 하지만 socket.io에서는 그럴 필요가 없다. 위에서 보다시피 JavaScript Object를 바로 전달할 수 있다.
//http
const http = require(`http`);
//websocket
const WebSocket = require(`ws`);
//socketio
const {Server} = require(`socket.io`);
//express를 이용한 httpserver
const httpServer = http.createServer(app);
//socketio 서버
const wsServer = new Server(httpServer);
httpServer.listen(3000, ()=>{
console.log(`listening on port 3000`);
}); // 서버는 ws, http 프로토콜 모두 이해할 수 있게 된다!
wsServer.on(`connection`,(socket)=>{
socket.on(`enter_room`,(msg)=>console.log(msg));
});
서버에서
위와 같이 on을 이용해서 발생한 room 이벤트에 대해 클라이언트가 보낸 내용을 받아서 콘솔에 로깅해준다.
입력한 내용을 console에서 확인할 수 있다.
string이 아닌 js object도 확인가능하다.
emit을 이용해서 server에서 호출할 callback 함수를 보낼 수 있다.
wsServer.emit(이벤트이름,payload,callback)
wsServer.on(이벤트이름,(payload,callback)=>{})
emit으로 원하는 이벤트를 지정하고 payload를 보낼 수 있다.
payload는 string, js object 상관없이 보낼 수 있다.
또한 callback 함수를 emit으로 보낼 수 있다.
브라우저가 callback을 emit에 담아서 보내고 서버가 그 함수를 호출하면 함수는 브라우저에서 동작할 것이다.
socket.emit(`enter_room`,{payload : input.value},()=>{console.log(`this is callback`)});
브라우저에서
다음과 같이 emit에 callback 함수를 보낸다.
socket.on(`enter_room`,(msg,done)=>{
//payload console에 찍음
console.log(msg);
//done은 emit으로 보낸 callback 함수이고 서버에서 호출할 수 있다.
done();
});
서버에서
브라우저에서 보낸 callback을 서버에서 이렇게 호출할 수 있다. 서버에서 done을 호출하면 클라이언트에서 작동하여 클라이언트의 console에 this is callback이 찍힐 것이다.
대박 ㄷㄷ
socketio는 room 기능을 자체 제공한다
room은 꼭 화상 채팅과 영상 room을 의미하는 것이 아니다.
게임을 하거나 배달앱으로 배달 주문을 해서 경과를 실시간으로 확인하거나 모두 room 안에서 이뤄진다.
socket.join(방이름);
socketio에서 room에 참가하기 위해서는 join(방이름)을 이용한다.
socket.io의 홈페이지에서 이런 다양한 기능들을 확인할 수 있다.
socket.rooms
해당 socket이 들어가 있는 방의 목록
socket.onAny((event,args...) =>{..} )
아무 이벤트에 대해 반응한다.
즉 위 코드는 발생하는 모든 이벤트에 대해 그 이벤트를 콘솔에 찍어줄 것이다.
socket.id
socket은 id가 있다.
socket은 기본적으로 각자의 방에 들어가 있다. (서버-브라우저 연결된 방)
socket.id는 자기가 처음으로 들어가있는 방의 이름과 같다.
socket.leave(방이름)
해당 방을 나감
socket.to(방이름).emit(이벤트명,payload,callback)
또는
socket.to(방이름배열).emit(..)
to를 이용해서 해당 방에 있는 사람들에게 emit할 수 있다.
방의 모든사람에게 welcome emit하기
disconnectiong 이벤트는 방을 나갈껀데 아직 접속이 끊기지는 않은 그런 상태다
따라서 방을 나가면서 누구 님이 나갔습니다. 이렇게 메세지를 보낼 수 있다.
socketio 에서 제공하는 이벤트고 on으로 등록하면됨
실제로 접속이 끊겼을 때는 disconnect 이벤트를 이용해 등록한다
socket은 js object이므로 사용자가 입력한 닉네임을 받아서
socket["nickname"] = nickname
과 같이 지정해줘서 해당 socket의 닉네임을 설정할 수 있다.
Adapter는 다른 서버들 사이에 실시간 어플리케이션을 동기화한다.
클라이언트가 많아지면 서버를 여러 개 만들수도 있다
다른 서버에 있는 클라이언트들 끼리는 바로 메세지를 보낼 수 없겠지
그러면 아답터를 통해서 ?에 있는 어떤 DB를 거쳐서 다른 아답터를 통해 다른 서버로 보내야 한다.
Adapter는 내 application으로 가기 위한 window다.
Adapter를 통해 누가 연결되었는지, room이 얼마나 있는지 등을 알 수 있다.
지금은 당장 DB랑 연결하지 않았으니까 브라우저 메모리로 작동함
wsServer.sockets.adapter
를 console.log로 찍어보면
어플리케이션에 있는 room들을 확인할 수 있다.
또한 socket들의 ID도 확인할 수 있는데 위에서 설명했듯이 각 socket은 각자의 room에 들어가 있고 해당 room의 이름과 socket의 ID는 같다.
이렇게 socket 연결을 만들며 자동 생성된 room을 private room이라 하고 방이름을 입력해서 room을 만들면 그것은 public room이라고 할 수 있겠다.
rooms에서 모든 room의 이름을 찾고 해당 이름이 socket 목록의 socket id에 있다면 해당 room은 private room이고 아니라면 해당 room은 public room일 것이다.
이러한 동작은 javascript Map을 이용해서 가능하다.
new Map()으로 Map 객체를 만들고 set(키,값), get(키)로 다룰 수 있다.
get(키)에 해당하는 값이 없으면 undefined를 반환한다.
또한 Map을 forEach로 이렇게 value와 key를 iterate할 수 있다.
wsServer.sockets.emit(이벤트, fucntion)
으로 서버의 모든 socket에게 emit할 수 있다.
강의에서는 위 내용들을 이용해서
현재 존재하는 public rooms를 알아내서 방에 입장하기 전 목록에 띄우고 방시 사라지면 삭제하는 기능을 구현함
key : roomname, value : set{socketID, socketID, .. }
의 구조로 된 Map이다.
value는 set으로 방에 있는 socketID들을 저장하고 있다.
set.size로 해당 집합의 크기를 알 수 있다.
이런 식으로 roomName에 해당하는 방의 size 즉 socekt이 몇개 있는지 = 사람이 몇명인지 알 수 있다.
socketio를 위한 admin UI도 있다!