이제 프로젝트가 끝남과 동시에 또 수업을 시작하였습니다.
숨 돌릴 틈이 진짜 없는 느낌 ㅠㅡㅠ,,,
이번 시간에는 소켓에 대해 배웠습니다.
0. 소켓(socket)이란?
웹소켓은 HTTP와 달리 양방향 실시간 데이터 소통을 하기 위해 생겨난 기술입니다.
TCP/IP의 위에서 동작하는 HTTP와 달리 조금 더 밑에서 동작한다고 합니다.
소켓은 떨어져 있는 두 호스트를 연결해 주는 도구로써 인터페이스 역할을 한다고 합니다.
소켓을 통해 데이터를 주고 받는 것은 양방향 데이터 통신 채널을 만드는 것 같습니다.
- 소켓 통신 흐름도

하기의 블로그에 꽤나 쉽고 자세하게 나와있어서 읽어보시는 것을 추천드립니다.
https://helloworld-88.tistory.com/215
[기본] 소켓(SOCKET)통신 이란?
소켓통신 소켓(SOCKET)이란?소켓(Socket)은 프로세스가 드넓은 네트워크 세계로 데이터를 내보내거나 혹은 그 세계로부터 데이터를 받기 위한 실제적인 창구 역할을 한다. 그러므로 프로세스가 데
helloworld-88.tistory.com
1. web socket
웹 소켓 (줄여서 ws라고 부르는 듯) 은 앞서 알아본 소켓과는 다른 개념입니다.
저는 그거나 그거나인 줄 알았는데 아니더라고요,,,
소켓은 앞서 알아보았듯이 어떠한 두 개의 호스트를 연결하고 데이터를 주고받는
네트워크 프로그래밍의 일반적인 용어입니다.
반면 웹 소켓은 HTML5에서 도입된 웹의 표준 기술입니다.
웹 브라우저와 웹 서버가 실시간 양방향 통신 (핸드셰이크)를 통신 위한 특별한 프로토콜이라고 합니다.
빠르게 작동하고, 통신할 때 아주 적은 데이터를 이용하는 것이 장점입니다.
- 웹 소캣 이벤트
웹 소켓의 이벤트가 4가지 있습니다.
1-1. OPEN
socket.addEventListener('open', function (event) {
console.log('웹 소켓이 열렸습니다.');
});
클라이언트가 웹 소켓 서버에 성공적으로 연결되어 열렸을 때 발생하는 이벤트입니다.
1-2. MESSAGE
socket.addEventListener('message', function (event) {
console.log('서버에서 메시지 수신:', event.data);
});
서버에서 클라이언트로 메시지를 보낼 때 발생하는 이벤트입니다,
1-3. ERROR
socket.addEventListener('error', function (event) {
console.error('웹 소켓 오류 발생:', event);
});
웹 소켓 연결 중 오류가 있을 대 발생하는 이벤트입니다.
1-4. CLOSE
socket.addEventListener('close', function (event) {
console.log('웹 소켓이 닫혔습니다.');
});
웹 소켓 연결이 종료되었을 때 발생하는 이벤트입니다.
반면에, 웹 소켓 서버에서도 웹 소켓과 연결해서 이벤트를 처리해야 하는데
서버는 아무런 준비 없이 웹 소켓을 실행할 수 없습니다.
그래서 WS라는 모듈을 설치해서 클라이언트와 웹 소켓으로 주고받을 수 있습니다.
npm install ws
그리고 이벤트를 등록하고 처리하는 함수인 on을 통해 클라이언트와 소켓을 연결할 수 있습니다.
const ws = require('ws');
const server = app.listen(PORT, () => {
console.log(`http://localhost:${PORT}`);
})
const wsServer = new ws.Server({server}); // 웹 소켓 서버 접속
const sockets= []; // 빈 배열
// on : 이벤트 등록 함수
wsServer.on('connection', (socket) => {
sockets.push(socket); // 배열에 접속한 클라이언트 객체 추가
// 클라이언트 메세지 수신
socket.on('message', (message) => {
console.log(`클라이언트로 부터 받은 메세지 :: ${message}`);
// 웹 소켓 서버에 접속한 모든 클라이언트(브라우저 탭)에게 메세지 전송
// = 브로드캐스팅(여러 컴퓨터한테 데이터 전송)
sockets.forEach((socket) => {
socket.send(`${message}`);
});
});
socket.on('close', () => {
console.log('[클라이언트 연결 종료]')
})
})
2. socket.io
socket.io는 자바스크립트의 라이브러리로 기본적으로 웹 소켓을 위해 구축되었습니다.
저희 같은 개발자가 웹 소켓을 좀 더 쉽고 간편하게 쓰도록 도와주는 라이브러리입니다.
여기에도 웹 소켓과 같은 기본 이벤트가 있습니다.
1-1. CONNECTION
io.on('connection', function (socket) {
console.log('새로운 클라이언트가 연결되었습니다.');
});
클라이언트가 서버에 연결되었을 때 발생하는 이벤트입니다.
1-2. DISCONNECT
socket.on('disconnect', function () {
console.log('클라이언트가 연결을 종료했습니다.');
});
클라이언트가 소켓에 대한 연결을 해제했을 때 발생하는 이벤트입니다.
1-3. ERROR
socket.on('error', function (error) {
console.error('에러 발생:', error);
});
연결 중 오류가 발생했을 때 발생하는 이벤트입니다.
1-4. CUSTOM
// 서버에서 사용자 정의 이벤트 발생
socket.emit('customEvent', { message: '사용자 정의 이벤트 발생' });
// 클라이언트에서 사용자 정의 이벤트 수신
socket.on('customEvent', function (data) {
console.log('사용자 정의 이벤트 수신:', data.message);
});
저희가 원하는 이벤트 이름으로 설정하고 사용할 수 있습니다.
여기서 헷갈렸던 건데, emit이 보내는 쪽이고 on이 받는 쪽입니다!!!
저희는 이러한 내용을 바탕으로 간단한 단체 채팅방을 구현했었는데요
먼저, 카카오톡처럼 단체 채팅에서 입장과 퇴장을 나타내는 소켓을 구현해 보겠습니다.


client 측 코드
// 입장할 때 !!
<div class="entry-box">
<input
type="text"
id="nickname"
placeholder="닉네임"
autofocus
onkeypress="if(window.event.keyCode==13){join()}"
/>
<button type="button" onclick="join();">입장</button>
</div><br />
<script>
// 채팅방 입장 시 setNick을 통해 닉네임을 서버측에 보냄 (닉네임 중복 검사를 위해)
function join() {
socket.emit('setNick', document.querySelector('#nickname').value); }
socket.on('notice', (msg) => {
document.querySelector('.chat-list').insertAdjacentHTML('beforeend',
`<div style="justify-items: center; text-align: center; text-color: gray; font-size: 10px;">${msg}</div>`)
});
</script>
첫 번째 입장 창을 거쳐 join 함수를 통해 서버 소켓으로 'setNick'이라는 커스텀이벤트로 전달하고 있습니다.
server 측 코드
socket.on('setNick', (nick) => {
console.log(`닉네임 설정 완료 :: ${nick}님 입장`);
console.log('접속 유저 목록 :: ', nickArray);
// 프론트에서 입력한 nick이 nickObs 객체에 존재하는지 검사
// 이미 존재: error 이벤트 + '이미 존재하는 닉네임 입니다'
// 새 닉네임: notice 이벤트 + '00님이 입장하셨습니다.'
if (Object.values(nickArray).indexOf(nick) > -1 ) {
socket.emit('error', `이미 존재하는 닉네임입니다.`);
} else {
// 새로운 닉네임
nickArray[socket.id] = nick;
socket.emit('entrySuccess', nick); // 해당 소켓 데이터 전송
io.emit('notice', `${nick}님이 입장하셨습니다.`);
io.emit('updateNicks', nickArray); // 전체 사용자 닉네임 모음 객체 전달
updateList();
}
})
server에서는 setNick을 받고 있고 콜백함수로 nick을 받아서
이미 존재하는 닉네임인지 확인하고, 만약 새로운 닉네임이라면
입장해서 'notice'라는 커스텀 이벤트로 메시지와 함께 클라이언트로 보내고 있습니다.
client 측 코드
socket.on('notice', (msg) => {
document.querySelector('.chat-list').insertAdjacentHTML('beforeend',
`<div
style="justify-items: center; text-align: center;
text-color: gray; font-size: 10px;">
${msg}
</div>`)
});
그럼 socket.on의 'notice'를 통해서 chat-list에 div를 삽입해서 '${nick}님이 입장하셨습니다.'라는
문구가 사용자에게 보이게 됩니다.
퇴장도 마찬가지로 client 측의 notice를 이용하여 msg만 바꿔서 이용합니다.
이번엔 custom 이벤트가 아니라 socket.io의 기본 이벤트인
disconnect 이벤트를 사용해서 퇴장을 공지합니다.
server 측 코드
socket.on('disconnect', () => {
console.log(`접속 끊김 :: ${socket.id}`);
io.emit('notice', `${nickArray[socket.id]}님이 퇴장하셨습니다.`);
})
이제 메시지 기능을 어떻게 구현할 수 있는지 알아보겠습니다.
저는 html에서 my msg라는 부분과 other msg라는 부분이 나눠져 있습니다.
my msg는 내가 보내서 채팅이 오른쪽에 있고, other msg는 남이 보낸 메시지로 채팅이 왼쪽에 위치합니다.

client 측 코드
function send() {
socket.emit('send', {
nick: myNick,
msg: document.querySelector('.input-msg').value});
document.querySelector('.input-msg').value = '';
}
socket.on('sendMsg', (data) => {
if (data.nick === myNick){
document.querySelector('.chat-list').insertAdjacentHTML('beforeend',
`<div class="my-chat">
<div class="my-chat-msg">${data.msg}</div>
<div class="my-pic">${data.nick}</div>
</div>`);
} else {
document.querySelector('.chat-list').insertAdjacentHTML('beforeend',
`<div class="other-chat">
<div class="other-pic">${data.nick}</div>
<div class="other-chat-msg"> ${data.msg}</div>
</div>`);
}
})
chat-list라는 div가 있어서, 만약 내 닉네임과 일치한다면,
my-chat이라는 div를 추가해서 오른쪽에 div를 생성해서 붙이는 방식을 사용합니다.
반대로 만약 내 닉네임과 일치하지 않는다면
other-chat이라는 div를 추가해서 왼쪽에 생성하여 붙이는 방식을 사용합니다.
server 측 코드
socket.on('send', (data) => {
io.emit('sendMsg', data);
})
저희는 단체메시지 방이고, 개인 DM 기능은 하지 않아서 socket의 send로 닉네임과 메시지를 받은 다음
io (전체에 소켓을 보냄)으로 emit을 통해 client 측에 보냅니다.
그럼 my 메시지인지 other 메세지인지 판별해서 메세지가 잘 뜨고
메세지 도중에 입장하거나 퇴장한 사람이 있다면 계속 div를 붙이는 방식이기 때문에
잘 나오게 됩니다.

이제 귓속말 기능도 넣고, css 도 디벨롭 해 볼 예정입니다 :)
감사합니다.
'개발 공부한 것들 > SeSSAC 웹 풀스텍 과정 회고록' 카테고리의 다른 글
| [SeSSAC] 웹 풀스택 영등포 5기 과정_SpringBoot_dto,vo,axios, API (2) | 2023.12.07 |
|---|---|
| [SeSSAC] 웹 풀스택 영등포 5기 과정_Java(Class) (2) | 2023.11.25 |
| SeSSAC 웹 풀스텍 과정 회고록[SeSSAC] 웹 풀스택 영등포 5기 과정_2차 프로젝트 회고록 (0) | 2023.11.14 |
| [SeSSAC] 웹 풀스택 영등포 5기 과정_REACT(7)_Redux (0) | 2023.10.22 |
| [SeSSAC] 웹 풀스택 영등포 5기 과정_REACT(6)_Routing, Form (1) | 2023.10.17 |