Socket서버 만들어 보기

Ricky·2020년 10월 25일
1
post-custom-banner

Socket서버 만들어 보기

pusher 모듈을 대신하기 위한 웹 소켓 서버


pusher에 메세지 전송 기능만을 사용하고 있어서 Socket.io를 사용하여 직접 구현해 보기로 하였다.

Socet.io

클라이언트와 웹소켓 연결을 위한 라이브러리

Socket.IO

구조

index.js              // express 서버구동

src
	- api               // socket API 
	- socket            // socket 연결, init
	- initializers      // 공통모듈 (미들웨어 등등)

서버구동을 위하여 node의 프레임워크인 express를 사용하기로 하였다

experss

소켓 API 사용을 위한 서버

Express - Node.js web application framework

index.js (express 실행 파일)

import express from 'express';
import socket from './src/socket/mainSocket';
import http from 'http';
import scoketio from 'socket.io';

const app = express();
const server = http.createServer(app);
const io = scoketio(server);
// 네임스페이스 이름
const Io = io.of('{{nameSpaceName}}');

// 해당 네임스페이스 기본 설정
app.use(socket({ Io, newRedis }));

// Router 
app.use('/pusher', apiRouter({ io, newRedis }));
app.use('/other', otherRouter({ io, newRedis }));

server.listen(settings.PORT, (err) => {
  if (err) throw err;
  console.log(`listening on port ${settings.PORT}`);
});

index.js 에서 'app.use(socket({ Io, newRedis }));' 으로 원하는 소켓 서버를 설정 해준다.

/socket/mainSocket.js (socket)

import redis from '../config/redis';

const clients = {};

const socket = ({ Io, newRedis }) => {
  Io.on('connection', (socket) => {
		
    socket.on('login', (data) => {
			// 로그인시 룸네임 설정 
      socket.join(`presence-${{UserRomName}}`, () => {
        const [socketId, roomName] = Object.keys(socket.rooms);
				
        const redisData = {
          socketId,
          roomName,
          setDate: Date(),
          user: data.user,
        };
				// 정보 확인을 위한 redis 저장
        newRedis.set(`{{nameSpaceName}}-${data.user.m_no}-${socketId}`, JSON.stringify(redisData), 'ex', redis.redisConfig.ttl);

        clients[socketId] = {
          ...data,
					roomName
        };
      });
    });

		// ... 필요한 기능들을 추가 하시면 됩니다. 

    socket.on('disconnect', () => {
      
      const data = clients[socket.id];

			// 연결이 끊어졌을때 room , redis 삭제
      socket.leave(`presence-${{UserRomName}}`);
      newRedis.del(`{{nameSpaceName}}-${data.m_no}-${socket.id}`);

      delete clients[socket.id];
    });

    socket.on('error', (err) => {
      console.log('received error from socket:', socket.id);
    });
  });

  return (req, res, next) => next();
};

export default socket;

pusher 의 기능을 대신하는 api로 사용

// API 주소 : {URL}/pusher/.... 
app.use('/pusher', apiRouter({ io, newRedis }));
// 다른 기능의 API필요할 경우
app.use('/other', otherRouter({ io, newRedis }));

해당 라우터에서 프론트로 전송처리

하나는 지정 룸 전송, 하나는 네임스페이스 전체에 처리

import express from 'express';

const apiRouter = (api) => {
  const router = express.Router();

  // roomName 메세지 전달
  router.post('/sendMessage', (req, res, next) => {
		/*
		  nameSpace
		  roomName
		  sendMessage
		  sendData
		*/
    const { data } = req;

    api.io.of(data.nameSpace).to(data.roomName).emit(data.sendMessage, data.sendData);

    res.json('success').end();
  });

  // nameSpace 전체 전송
  router.post('/allMessage', (req, res, next) => {
    const { data } = req;

    api.io.of(data.nameSpace).emit(data.sendMessage, data.sendData);

    res.json('success').end();
  });

  router.all('/*', (req, res) => {
    res.status(404)
      .json({ code: 404, message: '없는 API' })
      .end();
  });
  return router;
};
export default apiRouter;

위의 설정으로 정상적으로 소캣서버를 구현하였다.

Client

현재 프론트에서 angularjs 를 사용하고 있어 해당기준으로 생성하였다

bower sokcet.io-client

socket.io-client on Bower

// 모듈 설치
$ bower install socket.io-client

// index.html
<script src="/socket.io/socket.io.js"></script>

socket.Io 서비스 생성

'use strict';

angular.module('App')
  .factory('socketIo', function (userInfo) {
    const m_no = userInfo.user.m_no;

    return {
			// 소켓 첫 연결
      socketConnect: () => {
        if (userInfo != {}) {
          const socket = io.connect(`{{Your Socket server}}`);

          socket.on('connect', () => {
            socket.emit('login', userInfo);
          });

          socket.on('disconnect', () => {
            console.log(`socket client disconnect...(ws-${m_no}-${socket.id})`);
          });

          return socket;
        }
      },

			// 수신 메세지 설정
      init: (socket) => {
        socket.on('logout', (data) => {
          if (data.m_no === m_no) {
            // 확인 버튼 클릭하기전에 새로고침 할수도 있으니 토큰 먼저 지움
            socket.emit('logout', userInfo);
         
          }
        });
				//... pusher 에서 사용하던 기능들 등록
      }
    };
  });

메시지를 추가해야 할 경우 새로운 메세지 이름을 설정하고 사용

socket.on('new_messasge_nema', (data) => {
	// .. 기능
})

Back End

socket Initializer 생성

프론트에서 선언한 메세지명 전달 데이터로 소켓 서버에 request 호출하여 사용

// 소켓 서버 API 호출 (romm)
sendMessage: async (data) => {
  const url = `${config.socket.url}/pusher/allMessage`;
  const params = {
    nameSpace,
    roomName,
    sendMessage,
    sendData
  };
  await api.request.sendUrlJson(
    'POST',
    url,
    params
  );
},

// 소켓 서버 API 호출 (전체)
sendAllMessage: async (data) => {
//..
}

이렇게 socket 기능을 구현해 보았다.

profile
Developer
post-custom-banner

0개의 댓글