본문 바로가기

3.구현/HTML5&Javascript

[node.js] websocket 사용하기

웹소켓은 웹 환경에서 웹소켓 클라이언트로 사용하는 예제이다.1

작성자: ospace114@empal.com, http://ospace.tistory.com/

var ws = new WebSocket('ws://localhost:3001');
ws.onopen = function (event) {
    ws.send("Client message: Hi!");
}
ws.onmessage = function (event) {
    console.log("Server message: ", event.data);
}
ws.onerror = function (event) {
    console.log("Server error message: ", event.data);
}

웹소켓 서버

웹소켓 서버 구현하기 위해서는 ws 패키지를 사용했다.

const ws = require('ws');
const wsServer = new ws.Server({port:3001});
wsServer.on('connection', function(socket) {
    socket.send("Hello! I am a server.");
    socket.on("message", function(message) {
        console.log("Received: %s", message);
    });
});

http 서버와 같이 사용하는 경우이다.

const fs = require('fs');
const https = require('https');
const ws = require('ws');
const server = https.createServer({
  cert: fs.readFileSync('/path/to/cert.pem'),
  key: fs.readFileSync('/path/to/key.pem')
});
const wss = new ws.Server({ server });
wss.on('connection', function connection(socket) {
  socket.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
  socket.send('something');
});
server.listen(8080);

socket.io 사용

socket.io 사용하는 방법이 있다. 일반적인 웹소켓은 예전 브라우저에서는 지원하지 않기에 호환성은 socket.io가 더 좋다.
이는 브라우저 기본 지원은 아니기 때문에 별도로 js 추가해서 사용해야한다. socket.io에서 각 브라우저 기술을 파악해서 적합한 기술을 선택해서 통신한다.

npm i socket.io

일단 express.js를 사용한다고 간주하겠다.
서버코드는 다음과 같다.

var socketIo = require('socket.io');
var http = require('http');
var server = http.createServer(app);
const io = new socketIo.Server(server);
//const io = socketIo(3000);
io.on('connection', (socket) => {
  console.log('a user connected');
});

클라이언트 코드는 다음과 같다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.min.js"></script>
<script type="text/javascript">
    const socket = io();
</script>

사용자 단위로 관리

특정사용자에 대한 데이터 관리하는 예제이다.

const sockets = {};
function sendTo(user, data) {
    if(sockets[user] && sockets[user].readyState === WebSocket.OPEN)
        sockets[user].send(data);
}
wss.on('connection', (socket) => {
    const userId = userIdOf(socket);
    sockets[userId] = socket;
    socket.on('message', function incoming(message) {
        // userId로 처리 가능
    });
    socket.on('close', function incoming(message) {
        delete sockets[userId];
    });
});

userIdOf()은 자신의 메시지에 맞게 구현해주면 된다.

접근 관리

server.on('upgrade', function(req, socket, head) {
    const pathname = url.parse(req.url).pathname;
    let remoteIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    let protocol = req.headers['sec-websocket-protocol'];

    // 인증 검증
    const auth = protocol && jwt.verify(protocol);
    if (!auth) {
      console.error(`unauthorized from ${remoteIp}: ${protocol}`);
      socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
      socket.destroy();
      return;
    }

    console.log(auth);
    console.log(`authorized from ${remoteIp} by userId[${auth.userId}]`);

    // 경로 확인
    if(pathname === '/alarms') {
        wsServer.handleUpgrade(req, socket, head, function(conn) {
            wsServer.emit('connection', conn, auth);
        })
    } else {
        console.error('invalid upgrade:', pathname);
        socket.destroy();
    }
});

var sockets = {};
const wsServer = new ws.Server({noServer:true});

wsServer.on('connection', function(socket, req) {
  let userId = userIdOf(req);
  sockets[userId] = socket;

  console.log(`ws connected - userId[${userId}]`);

  socket.on("message", function(message) {
    console.log("Received: %s", message);
  });

  socket.on('error', function(err:any) {
      console.error(`ws error - userId[${userId}]`, err);
  });

  socket.on('close', function(ws:any) {
      delete sockets[userId];
  })
});

참고

[1] https://poiemaweb.com/nodejs-socketio
[2] https://medium.com/@raj_36650/integrate-socket-io-with-node-js-express-2292ca13d891

반응형