지금 진행하고있는 프로젝트는 실시간 채팅 기능을 지원합니다. 그래서 실시간 채팅 기능을 구현하기 위해 socket.io를 사용하기로 했습니다.
class App {
public app: express.Application;
public port: number;
public server: any;
public io: socketIO.Server;
constructor(port) {
if (!this.app) {
this.app = express();
this.port = port;
this.initializeMiddlewares();
}
}
private initializeMiddlewares() {
createConnection(config)
.then(() => {
console.log('Database Connected :)');
})
.catch((error) => console.log(error));
this.app.use(cookieParser());
this.app.use(cors({
.
.
.
.
이번 프로젝트에서는 app.ts와 server.ts로 분리하여 서버의 실행은 server.ts에서 담당하게 하고 나머지는 app.ts에서 담당하게 하여 역할을 분리하였습니다.
app.ts를 클래스로 구현하여 사용했는데요. express에서 typescript를 사용하기 위해 자료를 찾아보던 중 클래스로 구현하여 사용할 변수들의 타입을 미리 지정하여 사용하는 자료가 있어 한번 사용해 보았습니다. 하지만 익숙하지 않은 구조를 사용해서 그런지 조금 어려움을 겪었는데요...
오늘 작성한 socket.io 부분 코드입니다.
public listen() {
this.server = this.app.listen(this.port, () => {
console.log(`App listening on the port ${this.port}`);
});
this.io = socketIO(this.server);
this.io.on('connection', (socket) => {
console.log('user connect');
.
.
.
.
위의 코드를 보면 app.listen()으로 서버를 실행하여 실행한 서버 인스턴스를 this.server에 담아주고 그것을 socket.io가 받아서 사용하고 있습니다. socket.io를 사용하기 위해서는 서버 인스턴스를 넘겨주어야 하는데 class로 만들어서 조금은 헷갈려 this.io를 app class 내부에 선언을 해줘야 하는지, 아니면 위의 코드와 같이 선언해 줘야 하는지 이것저것 테스트를 해보다가 위의 코드를 실행하여 정상 작동하였습니다.
혹시 누군가 제 글을 보시는 분중 typescript와 express를 사용하는데 app을 class로 만드신다면 참고가 될수 있겠습니다.
삽질은 제가 다 해놨습니다! ㅎㅎ 사실 코드를 잘 이해하고 있었다면 삽질할 일도 없었지만...
아무튼! 잘 작동하는 모습을 보니 기분이 좋습니다 ㅎ
로컬 서버에서 켜지긴 했으나 AWS 서버로 옮겨 실제 클라이언트와 통신을 하려고하니 이와 같은 에러가 발생했습니다.
GET /socket.io/?EIO=3&transport=polling&t=Mctq2Fg 404
왜 잘켜지는데 작동을 못하니..
한참을 삽질한 끝에 websocket에 대한 기본적인 지식이 부족했다는 사실을 알아습니다.
실시간 채팅을 구현하는 방법은 여러가지가 있다. 내가 알아본 방식은 크게 4가지 방법이 있었습니다.
위의 에러에 따르면 클라이언트에서는 polling 방식으로 요청을 보내는데 서버에서는 websocket으로 받고있어서 서로를 찾지 못하고 있었습니다.
polling은 클라이언트에서 일정한 주기로 계속해서 요청을 보내고 서버에 응답이 있으면 받아오는 식으로 통신을 한다. 즉 클라이언트에서 계속에서 서버에 '응답 있음? 응답 있음?'하고 물어보는 것이다. 누군가가 서버에 채팅을 보내 서버가 응답해줄 채팅이 있다면 그때 응답에 채팅을 담아 보내주는 것이다. 하지만 polling 방식은 불필요한 요청을 계속해서 보내기 때문에 과부화가 걸릴수 있다.
Long polling과 polling의 차이점은 long polling은 요청을 보내고 서버가 응답 혹은 timeout을 보내줄때까지 응답을 대기하고 있는다는 것이다. 그러다가 응답이 오면 다시 요청을 보내고 이를 반복한다.
스트리밍은 말그대로 방송을 듣는다고 생각하면 편하다. 서버가 클라이언트에게 보내줄 응답 데이터가 있다면 클라이언트는 그때그때 서버로부터 데이터를 받을수 있다. 하지만 클라이언트가 서버에게 요청을 보내기가 어렵다.
웹소켓 통신은 우리가 일반적으로 생각하는? 실시간 통신과 가장 유사하다. 클라이언트와 서버는 최초 통신시 handshake라는 작업을 하게된다. 이 handshake라는 작업을 하게되면 클라이언트는 서버에게 이벤트가 발생할때만 request를 보내면 되고, 반대로 서버도 클라이언트에게 보내줄 response가 있다면 클라이언트가 요청하지 않더라도 데이터를 보내줄수가 있는것이다. websocket 방식은 현재 실시간 통신에서 가장 보편적으로 사용되고 있다.
여기까지 실시간 통신의 대표적인 방법에 대해 살표보았는데요. socket.io를 사용하여 통신할때 별도로 옵션을 지정하지 않는다면 디폴트 값인 polling으로 서버에 요청을 보낸다는 사실을 몰랐었습니다... 그래서 클라이언트의 요청을 서버가 수신하지 못했었는데요. 다음과 같이 옵션을 주니 정상적으로 실시간 채팅 서버를 구현할 수 있었습니다.
//server
this.io = socketIO(this.server, {
requestCert: true,
secure: true,
rejectUnauthorized: false,
transports: ['websocket'], //통신 방법
});
서버는 요로코롬 해주시고
//client
const newSocket = io('https://modurun.xyz', {
transports: ['websocket'],
upgrade: false,
forceNew: true,
});
클라이언트도 요로코롬 서로 transports를 맞춰 주시면 됩니다!
처음 실시간 채팅을 구현할때 websocket통신에 대한 기초적인 지식이 없어 한참 삽질을 했는데 라이브러리 사용 이전에 해당 기술에 대해 꼭! 먼저 공부하고 사용해할것 같습니다
어디서 어떤 코드를 작성했는지 정확히 이해하기 힘듭니다..
github 주소 있을까요?