소켓 통신 사용하는 이유
소켓 통신은 실시간 통신을 할 수 있고 HTTP 통신보다 효율적으로 통신을 할 수 있습니다.
HTTP와 소켓 차이
HTTP 통신
- HTTP 통신은 클라이언트에서 서버로 요청을 보내고 서버가 응답하는 방식으로 통신이 이루어진다. 응답에는 클라이언트의 요청에 따른 결과를 반환한다.
- 클라이언트의 요청이 있을 때 서버가 응답하는 방식(단방향 통신)
- 최근에는 Keep Alive 옵션을 통해 일정 기간 동안 클라이언트와 Connection을 유지하는 방식으로 통신이 가능해졌다.
소켓 통신
- 클라이언트와 서버 양쪽에서 서로에게 데이터 전달을 하는 방식의 양방향 통신
- 보통 스트리밍이나 실시간 채팅 등 실시간으로 데이터를 주고 받아야 하는 경우 Connection을 자주 맺고 끊는 HTTP 통신보다 소켓 통신이 적합하다.
- 대신 Connection을 하고 있기 때문에 HTTP보다 리소스가 더 소모된다.
소켓 통신 구현
socket.io 모듈을 이용해서 구현
socket.io 모듈과 ws 모듈이 있는데 socket.io를 선택한 이유
https://velog.io/@jguuun/Socketio-WS-diff
웹소켓 Socket.io와 WS의 차이
두 모듈을 사용하다보니 세세하게 차이가 나는 것을 알 수 있었습니다. ws는 조금 불친절하지만 원하는대로 코드 작성하기가 쉬웠고, socket.io는 기능이 많고 쉽게 사용하기 쉬우며 직관적입니다.
velog.io
최초 접속은 http로 접속하고 통신은 ws 프로토콜을 이용해서 통신을 합니다.
// 해당 이벤트를 받고 콜백함수를 실행
socket.on('받을 이벤트 명', (msg) => {
})
// 이벤트 명을 지정하고 메세지를 보낸다.
socket.emit('전송할 이벤트 명', msg)
1. socket.io 설치
일단 socket.io 모듈을 설치해줍니다.
npm i socket.io --save
Server측
- 클라이언트에서 socket.io 서버에 접속하게 되면 connection 이벤트가 발생하면서 event handler를 수행하게 됩니다.
//index.js
//http 모듈을 사용하여 Express 애플리케이션(app)을 기반으로 HTTP 서버를 생성합니다.
import { io } from './socket.js';
let server = http.createServer(app);
//Socket.IO의 Server 클래스를 사용하여 Socket.IO 서버를 만듭니다.
let socket = new Server(server,{
cors : {
origin : "http://localhost:3000"
}
});
//socket.js 파일에 있는 io 함수를 사용
io(socket);
//HTTP 서버가 환경 변수 SERVER_PORT에 지정된 포트에서 리스닝을 시작하도록 설정합니다.
server.listen(process.env.SERVER_PORT, () => {
console.log(`server is ready, ${process.env.SERVER_PORT}`);
});
// socket.js
import { saveUser, checkUser } from './srcs/controllers/memberController.js';
import { saveChat } from './srcs/controllers/chatController.js'
//클라이언트가 서버에 연결되면 실행됩니다.
//socket 객체는 연결된 클라이언트와의 소켓 통신을 담당합니다.
export const io = (io) => {
io.on("connection", (socket) => {
//접속한 클라이언트 소켓ID 단, 새탭으로 들어오면 바뀐다.
console.log("접속한 클라이언트의 socketid" + socket.id);
socket.on("newUser" ,async (userName, cb) => {
console.log("새로운 유저: ", userName);
//유저 저장
let user = await saveUser(userName,socket.id);
cb({ ok : true, data : user}) ;
})
socket.on("sendMessage", async (message,cb) =>{
//const newMessage = await memberController.saveChat(message);
console.log("메세지: ", message);
//유저 찾기
let user = await checkUser(socket.id);
//채팅 저장
let newMessage = await saveChat(message,user);
io.emit("message", newMessage)
})
//연결이 종료된 경우
socket.on("disconnect", () => {
// 나가는 사람을 제외한 나머지 유저에게 메시지 전송
console.log("연결해제")
});
});
};
Client 측
//server.js
//socket.io-client 패키지에서 io 함수를 가져옵니다. 이 함수는 Socket.IO 서버에 대한 연결을 설정하는 데 사용됩니다.
import { io } from "socket.io-client"
// 해당 ip의 socket 서버에 접속
export const socket = io("http://localhost:3001")
//index.js
import "./App.css";
import { useEffect, useState } from "react"
import { socket } from './server.js'
import InputField from './components/InputField/InputField.jsx'
import MessageContainer from './components/MessageContainer/MessageContainer.js'
function App() {
const [user, setUser] = useState(null);
const [message, setMessage] = useState('')
const [messageList, setMessageList] = useState([])
useEffect(() => {
socket.on("message", (message) =>{
setMessageList((prev) => prev.concat(message));
});
askUserName();
}, [])
const askUserName = () =>{
const userName = prompt("유저 이름을 입력하세요")
socket.emit("newUser", userName, (res) =>{ //(대화 제목, 보낼 내용, res는 백엔드에서 보내오는 response값 콜백함수)
if(res?.ok){
setUser(res.data);
}
})
}
const sendMessage = (event) =>{
event.preventDefault();
socket.emit("sendMessage", message, (res) =>{
console.log(message)
})
}
return (
<div>
<div className="App"></div>
<MessageContainer messageList = {messageList} user = {user}/>
<InputField message = {message} setMessage= {setMessage} sendMessage = {sendMessage}/>
</div>
);
}
export default App;
client 코드 출처 : https://www.youtube.com/watch?v=uE9Ncr6qInQ
채팅방 구분해서 접속하기
Room & Namespace
- room은 Namespace의 하위 개념
) - 각 socket들은 참여할 수 있고 탈퇴할 수 있는 임의의 room을 정의할 수 있는데 이 room이라는 것은 채팅방이라고 생각하면 됩니다.
socket.on('joinRoom', async (room) =>{ // joinRoom을 클라이언트가 emit 했을 시 let roomName = room; // 클라이언트를 msg에 적힌 room으로 참여 시킴 socket.join(roomName); });
- Server
Client
socket.emit("joinRoom", "room1", (res)=>{
})
Socket admin-ui
- 현재 서버, 클라이언트, socket room정보, 소켓통신 상황을 한눈에 볼 수 있습니다.
//index.js
import { instrument } from '@socket.io/admin-ui'
const app = express();
let server = http.createServer(app);
let socket = new Server(server,{
cors : {
origin : ["http://localhost:3000",
"https://admin.socket.io"],
credentials: true
}
});
io(socket);
instrument(socket, {
auth: false,
});
server.listen(process.env.SERVER_PORT, () => {
console.log(`server is ready, ${process.env.SERVER_PORT}`);
});
출처:https://inpa.tistory.com/entry/SOCKET-%F0%9F%93%9A-Namespace-Room-%EA%B8%B0%EB%8A%A5
'Dev' 카테고리의 다른 글
위치 기반으로 글 조회 기능 구현 (1) | 2024.12.04 |
---|---|
fcm 이용해서 앱 푸쉬 구현 (0) | 2024.12.04 |
OCR로 영수증 데이터 가져와서 식품 데이터 분류하기(분류 모델 만들기) + Trouble shooting (0) | 2024.12.04 |
ElasticSearch로 검색 성능 높이기 (0) | 2024.12.04 |
Swagger 사용하기 (1) | 2024.12.04 |