본문 바로가기

프로그래밍/Node.js

[Do it! Node.js 프로그래밍] 11일차

1. 공부한 범위


[10] 채팅 서버 만들기



2. 공부한 내용


[10] 채팅 서버 만들기

 

10-1 soket.io 사용하기

 

soket.io를 사용하기 위해 모듈 설치하기

- soket을 위해서는 soket.io 모듈 뿐 아니라 cors 모듈도 설치해야 한다.

- CORS : 이것을 사용하면 클라이언트에서 Ajax를 통해 데이터를 가져올 때 현재 보고 있는 브라우저의 웹 문서를 제공한 웹 서버 외 다른 욉 서버에서도 접속할 수 있도록 제약을 해제할 수 있게 된다.

- socket.io와 cors를 모두 npm을 통해 설치한다. 이 과정을 마치면 socket.io를 사용할 준비가 끝난 것이다.

 

app.js 메인 파일에 기본 코드 하나씩 추가하기

- app.js파일 안에 require를 통해 socket.io와 cors 모듈을 등록한다.

- 그 후 app.use()메소드를 통해 cors를 미들웨어로 사용할 수 있도록 등록한다. 이때 cors코드는 라우터 미들웨어를 만드는 코드 바로 위에 추가해야 정상적으로 동작할 수 있다.

 

- 서버 객체를 실행하는 코드 아래에 웹 소켓 요청을 받을 수 있도록 해주는 코드를 추가해준다.

- socket.io 모듈에서 listen() 메소드를 호출해 웹 서버 객체를 파라미터로 전달하게 되면 이후에는 웹 소켓으로 들어오는 요청을 처리할 수 있게 된다.

- http 모듈로 실행한 익스프레스 서버는 server 변수에 저장되어 있기 때문에 반드시 server 변수를 선언한 이후에 io 변수를 선언해야 정상적으로 작동하게 된다.

- socket.io 모듈에서 클라이언트로부터 웹 소켓 요청을 처리할 수 있게 하는 메소드

attach(httpServer, options) : 웹 서버 인스턴스가 socket.io를 처리한다.

listen(httpServer, options) : attach 메소드와 같은 기능을 한다.

- 위의 attach와 listen은 같은 역할을 하여 어떤 것을 사용해도 에러가 발생하지는 않는다.

- socket.io 객체의 listen() 메소드를 호출한 코드 아랫부분에 이벤트 처리를 추가할 수 있다.

 

- connection 이벤트를 통해 콜백 함수쪽으로 소켓 객체가 전달되고 이 객체에는 접속한 클라이언트의 IP주소와 포트 번호를 확인할 수 있는 속성이 있어 해당 정보를 로그로 출력하게 된다.

 

사용자가 웹 브라우저에서 볼 웹 문서 만들기

 

- 소켓 서버에 제대로 연결이 될 수 있도록 사용자에게 시각적인 정보를 제공해주는 html이다.

 

- 소켓 서버에 제대로 연결될 수 있도록 스크립트를 작성한다.

- jQuery는 버전이 꾸준히 올라가기 때문에 jQuery 사이트로부터 최신 버전을 참조할 수 있도록 한다.

- 함수 내에서는 연결하기 버튼이 클릭되면 해당 버튼의 id값으로부터 문서의 요소를 찾아낸 후 bind() 메소드를 통해 이벤트를 바인딩하게 된다.

 

 

서버에 보낸 메시지를 그대로 받기

- socket.io 모듈은 메시지를 주고받을 때 이벤트 처리 방식을 사용한다. 이벤트를 처리할 때와 같은 코드를 통해 메시지를 주고받을 수 있다는 것이다.

- 이벤트 취급을 받기 때문에 on() 메소드로 이벤트 처리 함수를 등록한다면 전달받은 데이터를 처리할 수 있게 된다.

- 데이터를 보낼 때는 emit() 메소드를 통해야 하며 이 메소드는 클라이언트에서 서버로 메시지를 보내거나 서버에서 클라이언트로 메시지를 보낼 수 있도록 해준다.

- 송수신 이벤트를 처리해주는 메소드

on(event, callback) : 이벤트 수신 형태로 메시지를 수신했을 때 처리할 콜백 함수를 등록한다. 콜백함수의 파라미터로는 수신한 객체가 전달된다.

emit(event, callback) : 이벤트 송신 형태로 메시지를 송신한다.

- Echo 기능을 만듦으로써 서버에 보낸 메시지를 그대로 받아볼 수 있다.

- Echo 기능은 클라이언트에서 서버로 데이터를 보내고 받는 가장 기초적인 과정으로 네트워크의 첫 단계로 많이 거쳐간다.

 

- 소켓 서버로 연결을 수행하는 'connect' 이벤트 내에 'message' 이벤트를 추가한다. 이 이벤트는 클라이언트가 보낸 메시지를 그대로 다시 돌려받는 역할을 수행한다.

- 서버에 연결되기 전에도 데이터 송 수신 관련 이벤트를 처리할 수 있도록 등록해도 괜찮다.

- 위 Echo에서 출력될 메시지 내용은 아래와 같다.

sender : 보내는 사람의 아이디가 들어간다.

recepient : 받는 사람의 아이디가 들어간다.

commend : 보내는 데이터의 종류를 구별하는 속성으로 위 코드에서는 단순히 메시지일 뿐이기 때문에 'chat' 값을 넣는다.

type : 전송될 데이터의 형태를 지정한다.

data : 데이터가 들어간다.

 

- app.js 내의 connect 이벤트를 처리하는 함수에 해당 코드를 추가한다.

- 서버에 연결된 모든 클라이언트 소켓은 io.sockets 안에 들어있기 때문에 해당 소켓 안에 들어있는 데이터를 전송하면 된다.

- 소켓들을 일일이 찾아 데이터를 전송하기 위해서는 io.sockets 객체의 emit() 메소드를 호출하면 된다. 이 방식을 통하게 된다면 받은 메시지를 수정하지 않고 그대로 모든 클라이언트에 보내주게 된다.

- 여러 사람에게 메시지를 전송하는 방식

io.sockets.emit(event, object) : 나를 포함해 모든 클라이언트에 전송한다.

socket.broadcast.emit(event, object) : 나를 제외한 모든 클라이언트에 전송한다.

 

10-2 일대일 채팅하기

 

- 1 : 1 채팅은 상대를 지정해 메시지를 보내야 하기 때문에 각 클라이언트마다 고유한 정보가 존재해야만 한다.

- 모바일용 메신저는 로그인 아이디보다는 전화번호를 아이디로 사용하는 편이 더 간편하게 서로를 구분지을 수 있다.

 

 

 

- 로그인 버튼 처리 함수에서는 사용자가 입력한 데이터를 모두 변수에 넣은 후 하나의 객체로 만들어야 한다.

 

- Object.keys() 메소드를 이용하면 로그인 ID들을 배열로 만들 수 있다.

- 아래의 응답 메시지를 전송하는 함수와 message 이벤트를 받았을 때의 콜백 함수도 수정한다.

 

- 특정한 소켓을 찾고자 한다면 아래의 코드를 사용해야 한다.

io.sockets.connected[login_ids[message.recepient]];

- 클라이언트가 로그인하지 않았다면 login_ids 객체에 해당 로그인 ID가 없을 수 있다.

- 배열의 요소들 중 특정 요소를 삭제하고 싶을 때는 delete 키워드나 splice() 메소드 등 여러 방법들을 사용할 수 있다.

 

10-3 그룹 채팅하기

 

- 그룹 채팅은 일대일 채팅과는 달리 방을 만들고 해당 방에 초대된 사람들끼리 동시에 메시지를 주고받게 된다.

 

방 만들기

- socket.io 모듈은 몇 명의 사용자를 한 방에 모아두고 해당 클라이언트에만 메시지를 전송할 수 있도록 돕는 기능도 존재한다.

- 일대일 채팅과 그룹 채팅의 가장 큰 차이는 채팅 방의 유무이다.

 

 

 

- 위 스크립트로 방의 아이디와 이름을 입력상자로부터 가져오며, 로그인한 사람의 아이디도 가져와 자바스크립트 객체로 만든 다음 room 이벤트 형태로 서버에 보낸다.

- room 이벤트로 보내질 객체의 속성들은 아래와 같다.

roomId : 방 고유의 번호를 표시한다.

roomName : 어떤 방인지 표시할 때 사용한다.

roomOwner : 방을 만든 방장을 표시한다.

command : 방을 어떻게 할 것인지 결정할 때 사용한다. 

 

 

 

- connectToServer 함수 내에 그룹 채팅에서 방과 관련된 이벤트 처리에 대한 것을 작성한다.

- 방 리스트는 웹 문서에 id가 roomList인 <div>태그에 넣어야 하기 때문에 <p>태그를 전부 추가한다.

 

- room 이벤트를 받았을 때 app.js에서는 클라이언트로부터 command 속성값이 어떤것인지를 확인해야 한다.

- command의 속성값은 3개가 있으며 create,  update, delete다.

- create일 때는 방을 새로 만들어야 하는데, socket.io 모듈에서의 소켓 객체 join() 메소드를 사용해 방을 만들 수 있다.

- 방의 출입을 처리하는 소켓 객체의 메소드

join(roomName) : 방이 있으면 방에 입장하며 방이 없으면 새로운 방을 만든 후 방에 참가하게 된다.

leave(roomName) : 방에서 나온다.

- 추가적으로 방 정보를 관리하고자 한다면 socket.io 모듈에서 제공하는 방 객체에 속성을 추가함으로서 쉽게 가능해진다.

- 해당 방 정보는 io.sockets.adapter.rooms에 들어 있다.

- command의 값이 update일 경우 방 id를 이용해 io.sockets.adapter.rooms에 들어 있는 방 객체를 하나 찾아 속성을 변경한 후 클라이언트로 변경된 방 리스트를 보내게 된다.

 

- 이 함수는 방 리스트를 배열로 만들어준다. 클라이언트에 보낼 객체에는 command 속성과 rooms 속성을 넣어주게 된다.

- command는 list, rooms는 배열로 설정해주게 된다.

- 해당 함수는 기본 방을 제외하고 사용자가 만든 방 리스트를 배열로 만든다.

 

그룹 채팅에서 메시지 보내기

 

- 방 입장하기 버튼을 누르게 되면 서버에 room 이벤트를 보낸다.

- 보내는 객체의 command값은 join으로, 방 나가기일 때의 command는 leave로 설정한다.