[Study] BE/Node.js

[포스코x코딩온] Socket

stop-zero 2023. 4. 18. 01:54
더보기

⚙️   네트워크 지식이 필요한 부분이었다고 생각한다.

처음 듣는다면 정말 멍 때리고 있을 것 같다.  학교 수업 좀 더 열심히 들을 걸 후회한다. 오늘도 뼈저리게 느끼고 가는 전공지식의 중요성...🤣

그렇지만 통신에 대해 빠져버리니 끝도 없이 공부할 게 계속해서 나온다. 더 깊게 공부하는 것이 맞는지, 코드를 구성하기 위한 지식만 이해하고 넘어가는 게 맞을까라는 의문이 든다. 

이해는 되지만,코드는 내 맘대로 안 짜져지는 슬픔이 있었기에 이론을 한 번 더 정리해보고 넘어가는 것도 많은 도움이 될 것 같다. 

소켓

소켓은 프로그램이 네트워크 상에서 데이터를 주고 받을 수 있도록 서버랑 클라이언트를 연결해주는 도구이다.  

휴대폰을 충전하고자 콘센트 구멍을 찾고 있었다. 그러나 구멍이 없는 벽에 코드를  넣는다 해도, 전기는 사용할 수 없다. 

이와 같이 서버(서버 컴퓨터)와 클라이언트(내가 사용하는 컴퓨터) 양쪽 모두 소켓이 열러 있어야 데이터를 보내고 받을 수 있다. 

 

소켓은 프로토콜, IP 주소, 포트로 정의된다. 

프로토콜 : 시스템 간의 원활한 통신을 수용하는 통신 규약

IP : 컴퓨터에 부여된 고유한 식별 주소

포트 : 같은 컴퓨터 내에서 프로그램을 식별하는 번호

 

소켓 흐름

서버

클라이언트 소켓의 연결 요청을 대기하고, 연결 요청이 오면 클라이언트 소켓을 생성해 통신을 가능하게 한다.

1. 연결 대상에 대한 정보가 없는 소켓을 생성한다. 

  • socket() : Socket 생성 함수

2. socket과 port 번호를 바인딩한다. 

: 같은 포트 번호를 사용할 수도 있으니 server socket이 고유한 port 번호를 사용할 수 있도록 소켓과 번호를 결합해주는 작업이다. 

  • bind() : ip와 port 번호 설정 함수

3. client 연결 요청 대기 -> 대기 상태를 지속하닥, 연결 요청이 오면 대기 상태를 종료한다. 

  • listen() : 클라이언트의 요청에 수신 대기열을 만드는 함수

4. client 연결 수립

: 최종적으로 연결 요청을 받고, socket 간의 연결을 수립한다.  연결이 끝나면 다시 다른 연결 요청을 위해 대기하거나 소켓을 닫는다. 

  • accept(): 클라이어트와의 연결을 기다리는 함수

 

클라이언트

통신 연결 요청을 보내는 곳이며, 실제로 데이터 송수신이 일어나는 곳이다. 

1. 연결 대상에 대한 정보가 없는 소켓을 생성한다. 

  • socket() : 소켓을 여는 함수

2.  연결 요청 : 연결하고 싶은 대상에게 요청을 보내고 ip 주소와 port 번호로 연결하고 싶은 대상을 특정한다. 요청에 대한 결과과 돌아와야 연결의 실행이 끝이다.

  • connect() : 통신할 서버의 설정된 ip와 port 번호에 통신을 시도하는 함수
  • 서버가 accept() 함수를 이용해 클라이언트의 sockect descripter 를 반환

3. 데이터 송수신 : 연결 요청처럼 결과가 돌아와야 실행이 종료된다. 그러나 송수신간의 차이점은 존재한다. 

송신 : 데이터를 언제, 얼마나 보내는 것인지 알 수 있다. 

수신 : 상대방이 언제 얼만큼의 데이터를 보내는지 알 수 없다. 

그렇기에 수신하는 api는 별도의 thread에서 진행한다. 

  • 클라이언트와 서버가 서로 read() writer() 를 반복하며 통신

4. socket 닫기  : 데이터 송수신이 사라지면 소켓을 닫는다. 

 

WebSocket

두 프로그램의 데이터 교환을 위한 통신 방법 중 하나이다.

양방향 소통을 위한 프로토콜, 빠르고 적은 데이터 , 단순히 듣고 보내는 것만 가능하다.

 

Socket.io

이벤트 기반, 양방향 통신을 하기 위한 웹 소켓 기술을 활용하는 라이브러리이다. 

방 개념을 이용해 일부 클라이언트에게만 데이터를 전송하는 브로드캐스팅이 가능하다. 

 

Socket.io 사용

 # socket.io 설치
 npm i socket.io

 

클라이언트에서 발생하는 이벤트는 개발자가 임의로 설정할 수 있다. 

// 해당 이벤트를 받고 콜백함수를 실행
socket.on('받을 이벤트 명', (msg) => {
})

// 이벤트 명을 지정하고 메세지를 보낸다.
socket.emit('전송할 이벤트 명', msg)

 

소켓 메세지 수신

// 접속된 모든 클라이언트에게 메시지를 전송한다
io.emit('event_name', msg);

// 메시지를 전송한 클라이언트에게만 메시지를 전송한다
socket.emit('event_name', msg);

// 메시지를 전송한 클라이언트를 제외한 모든 클라이언트에게 메시지를 전송한다
socket.broadcast.emit('event_name', msg);

// 특정 클라이언트에게만 메시지를 전송한다
io.to(id).emit('event_name', data);

소켓 메세지 송신

// 클라이언트와 소켓IO 연결됬는지 안됬는지 이벤트 실행. (채팅방에 누가 입장하였습니다/퇴장하였습니다 )
io.on('connection/disconnection', (socket) => {
});

// 클라이언트에서 지정한 이벤트가 emit되면 수신 발생
socket.on('event_name', (data) => {
});

 

소켓 서버 설정

const app = require("express")(); 
const server = app.listen(8000, ()=>{ });

 

소켓 io에 서버 정보 넘겨주고 구동

const SocketIO = require('socket.io');

// 서버 연결, path는 프론트와 일치시켜준다.
const io = SocketIO(server, { path: '/socket.io' });

 

소켓 연결에 성공하여 이벤트 통신

//* 웹소켓 연결 시
io.on('connection', (socket) => {

  //* 연결 종료 시
  socket.on('disconnect', () => {
     console.log('클라이언트 접속 해제', ip, socket.id);
     clearInterval(socket.interval);
  });

  //* 에러 시
  socket.on('error', (error) => {
     console.error(error);
  });

  //* 클라이언트로부터 메시지 수신
  socket.on('reply', (data) => { // reply라는 이벤트로 송신오면 메세지가 data인수에 담김
     console.log(data);
  });

  //* 클라이언트로 메세지 송신
  socket.emit('news', 'Hello Socket.IO'); // news라는 이벤트로 문자열을 포함하여 송신
});